forked from TrueCloudLab/frostfs-node
[#1513] Upgrade NeoFS SDK Go with changed netmap
package
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
24b4c1ecf4
commit
21d2f8f861
70 changed files with 876 additions and 990 deletions
|
@ -244,8 +244,8 @@ type NodeInfoRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeInfo returns information about the node from netmap.
|
// NodeInfo returns information about the node from netmap.
|
||||||
func (x NodeInfoRes) NodeInfo() *netmap.NodeInfo {
|
func (x NodeInfoRes) NodeInfo() netmap.NodeInfo {
|
||||||
return x.cliRes.NodeInfo()
|
return *x.cliRes.NodeInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LatestVersion returns the latest NeoFS API version in use.
|
// LatestVersion returns the latest NeoFS API version in use.
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
|
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
|
@ -69,12 +68,14 @@ It will be stored in sidechain when inner ring will accepts it.`,
|
||||||
placementPolicy, err := parseContainerPolicy(containerPolicy)
|
placementPolicy, err := parseContainerPolicy(containerPolicy)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
|
if containerSubnet != "" {
|
||||||
var subnetID subnetid.ID
|
var subnetID subnetid.ID
|
||||||
|
|
||||||
err = subnetID.DecodeString(containerSubnet)
|
err = subnetID.DecodeString(containerSubnet)
|
||||||
common.ExitOnErr(cmd, "could not parse subnetID: %w", err)
|
common.ExitOnErr(cmd, "could not parse subnetID: %w", err)
|
||||||
|
|
||||||
placementPolicy.SetSubnetID(&subnetID)
|
placementPolicy.RestrictSubnet(subnetID)
|
||||||
|
}
|
||||||
|
|
||||||
attributes, err := parseAttributes(containerAttributes)
|
attributes, err := parseAttributes(containerAttributes)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
@ -177,16 +178,17 @@ func parseContainerPolicy(policyString string) (*netmap.PlacementPolicy, error)
|
||||||
policyString = string(data)
|
policyString = string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := policy.Parse(policyString)
|
var result netmap.PlacementPolicy
|
||||||
|
|
||||||
|
err = result.DecodeString(policyString)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
common.PrintVerbose("Parsed QL encoded policy")
|
common.PrintVerbose("Parsed QL encoded policy")
|
||||||
return result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
result = netmap.NewPlacementPolicy()
|
|
||||||
if err = result.UnmarshalJSON([]byte(policyString)); err == nil {
|
if err = result.UnmarshalJSON([]byte(policyString)); err == nil {
|
||||||
common.PrintVerbose("Parsed JSON encoded policy")
|
common.PrintVerbose("Parsed JSON encoded policy")
|
||||||
return result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("can't parse placement policy")
|
return nil, errors.New("can't parse placement policy")
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
@ -12,7 +11,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/policy"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -85,6 +83,13 @@ func initContainerInfoCmd() {
|
||||||
flags.BoolVar(&containerJSON, "json", false, "print or dump container in JSON format")
|
flags.BoolVar(&containerJSON, "json", false, "print or dump container in JSON format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stringWriter cobra.Command
|
||||||
|
|
||||||
|
func (x *stringWriter) WriteString(s string) (n int, err error) {
|
||||||
|
(*cobra.Command)(x).Print(s)
|
||||||
|
return len(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
func prettyPrintContainer(cmd *cobra.Command, cnr *container.Container, jsonEncoding bool) {
|
func prettyPrintContainer(cmd *cobra.Command, cnr *container.Container, jsonEncoding bool) {
|
||||||
if cnr == nil {
|
if cnr == nil {
|
||||||
return
|
return
|
||||||
|
@ -137,8 +142,14 @@ func prettyPrintContainer(cmd *cobra.Command, cnr *container.Container, jsonEnco
|
||||||
cmd.Println("invalid nonce:", err)
|
cmd.Println("invalid nonce:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp := cnr.PlacementPolicy()
|
||||||
|
if pp == nil {
|
||||||
|
cmd.Println("missing placement policy")
|
||||||
|
} else {
|
||||||
cmd.Println("placement policy:")
|
cmd.Println("placement policy:")
|
||||||
cmd.Println(strings.Join(policy.Encode(cnr.PlacementPolicy()), "\n"))
|
common.ExitOnErr(cmd, "write policy: %w", pp.WriteStringTo((*stringWriter)(cmd)))
|
||||||
|
cmd.Println()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.BasicACL) {
|
func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.BasicACL) {
|
||||||
|
|
|
@ -9,13 +9,9 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
nmClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
type netCfgWriter cobra.Command
|
|
||||||
|
|
||||||
var netInfoCmd = &cobra.Command{
|
var netInfoCmd = &cobra.Command{
|
||||||
Use: "netinfo",
|
Use: "netinfo",
|
||||||
Short: "Get information about NeoFS network",
|
Short: "Get information about NeoFS network",
|
||||||
|
@ -39,21 +35,23 @@ var netInfoCmd = &cobra.Command{
|
||||||
|
|
||||||
cmd.Printf("Time per block: %s\n", time.Duration(netInfo.MsPerBlock())*time.Millisecond)
|
cmd.Printf("Time per block: %s\n", time.Duration(netInfo.MsPerBlock())*time.Millisecond)
|
||||||
|
|
||||||
netCfg := netInfo.NetworkConfig()
|
const format = " %s: %v\n"
|
||||||
|
|
||||||
cmd.Println("NeoFS network configuration")
|
cmd.Println("NeoFS network configuration (system)")
|
||||||
|
cmd.Printf(format, "Audit fee", netInfo.AuditFee())
|
||||||
|
cmd.Printf(format, "Storage price", netInfo.StoragePrice())
|
||||||
|
cmd.Printf(format, "Container fee", netInfo.ContainerFee())
|
||||||
|
cmd.Printf(format, "EigenTrust alpha", netInfo.EigenTrustAlpha())
|
||||||
|
cmd.Printf(format, "Number of EigenTrust iterations", netInfo.NumberOfEigenTrustIterations())
|
||||||
|
cmd.Printf(format, "Epoch duration", netInfo.EpochDuration())
|
||||||
|
cmd.Printf(format, "Inner Ring candidate fee", netInfo.IRCandidateFee())
|
||||||
|
cmd.Printf(format, "Maximum object size", netInfo.MaxObjectSize())
|
||||||
|
cmd.Printf(format, "Withdrawal fee", netInfo.WithdrawalFee())
|
||||||
|
|
||||||
err = nmClient.WriteConfig((*netCfgWriter)(cmd), func(f func(key []byte, val []byte) error) error {
|
cmd.Println("NeoFS network configuration (other)")
|
||||||
var err error
|
netInfo.IterateRawNetworkParameters(func(name string, value []byte) {
|
||||||
|
cmd.Printf(format, name, hex.EncodeToString(value))
|
||||||
netCfg.IterateParameters(func(prm *netmap.NetworkParameter) bool {
|
|
||||||
err = f(prm.Key(), prm.Value())
|
|
||||||
return err != nil
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
common.ExitOnErr(cmd, "read config: %w", err)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,57 +59,3 @@ func initNetInfoCmd() {
|
||||||
commonflags.Init(netInfoCmd)
|
commonflags.Init(netInfoCmd)
|
||||||
commonflags.InitAPI(netInfoCmd)
|
commonflags.InitAPI(netInfoCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *netCfgWriter) print(name string, v interface{}, unknown bool) {
|
|
||||||
var sUnknown string
|
|
||||||
|
|
||||||
if unknown {
|
|
||||||
sUnknown = " (unknown)"
|
|
||||||
}
|
|
||||||
|
|
||||||
(*cobra.Command)(x).Printf(" %s%s: %v\n", name, sUnknown, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) UnknownParameter(k string, v []byte) {
|
|
||||||
x.print(k, hex.EncodeToString(v), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) MaxObjectSize(v uint64) {
|
|
||||||
x.print("Maximum object size", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) BasicIncomeRate(v uint64) {
|
|
||||||
x.print("Basic income rate", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) AuditFee(v uint64) {
|
|
||||||
x.print("Audit fee", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) EpochDuration(v uint64) {
|
|
||||||
x.print("Epoch duration", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) ContainerFee(v uint64) {
|
|
||||||
x.print("Container fee", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) ContainerAliasFee(v uint64) {
|
|
||||||
x.print("Container alias fee", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) EigenTrustIterations(v uint64) {
|
|
||||||
x.print("Number EigenTrust of iterations", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) EigenTrustAlpha(v float64) {
|
|
||||||
x.print("EigenTrust α", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) InnerRingCandidateFee(v uint64) {
|
|
||||||
x.print("Inner Ring candidate fee", v, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *netCfgWriter) WithdrawFee(v uint64) {
|
|
||||||
x.print("Withdraw fee", v, false)
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ func initNodeInfoCmd() {
|
||||||
nodeInfoCmd.Flags().Bool(nodeInfoJSONFlag, false, "print node info in JSON format")
|
nodeInfoCmd.Flags().Bool(nodeInfoJSONFlag, false, "print node info in JSON format")
|
||||||
}
|
}
|
||||||
|
|
||||||
func prettyPrintNodeInfo(cmd *cobra.Command, i *netmap.NodeInfo) {
|
func prettyPrintNodeInfo(cmd *cobra.Command, i netmap.NodeInfo) {
|
||||||
isJSON, _ := cmd.Flags().GetBool(nodeInfoJSONFlag)
|
isJSON, _ := cmd.Flags().GetBool(nodeInfoJSONFlag)
|
||||||
if isJSON {
|
if isJSON {
|
||||||
common.PrettyPrintJSON(cmd, i, "node info")
|
common.PrettyPrintJSON(cmd, i, "node info")
|
||||||
|
@ -45,12 +45,24 @@ func prettyPrintNodeInfo(cmd *cobra.Command, i *netmap.NodeInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Println("key:", hex.EncodeToString(i.PublicKey()))
|
cmd.Println("key:", hex.EncodeToString(i.PublicKey()))
|
||||||
cmd.Println("state:", i.State())
|
|
||||||
netmap.IterateAllAddresses(i, func(s string) {
|
var stateWord string
|
||||||
|
switch {
|
||||||
|
default:
|
||||||
|
stateWord = "<undefined>"
|
||||||
|
case i.IsOnline():
|
||||||
|
stateWord = "online"
|
||||||
|
case i.IsOffline():
|
||||||
|
stateWord = "offline"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Println("state:", stateWord)
|
||||||
|
|
||||||
|
netmap.IterateNetworkEndpoints(i, func(s string) {
|
||||||
cmd.Println("address:", s)
|
cmd.Println("address:", s)
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, attribute := range i.Attributes() {
|
i.IterateAttributes(func(key, value string) {
|
||||||
cmd.Printf("attribute: %s=%s\n", attribute.Key(), attribute.Value())
|
cmd.Printf("attribute: %s=%s\n", key, value)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,69 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/config"
|
|
||||||
nodeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/node"
|
nodeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/node"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/attributes"
|
"github.com/nspcc-dev/neofs-node/pkg/util/attributes"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
func parseAttributes(c *cfg) {
|
||||||
// list of default values for well-known attributes
|
if nodeconfig.Relay(c.appCfg) {
|
||||||
defaultCapacity = 0
|
return
|
||||||
defaultPrice = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
func parseAttributes(c *config.Config) []netmap.NodeAttribute {
|
|
||||||
if nodeconfig.Relay(c) {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stringAttributes := nodeconfig.Attributes(c)
|
fatalOnErr(attributes.ReadNodeAttributes(&c.cfgNodeInfo.localInfo, nodeconfig.Attributes(c.appCfg)))
|
||||||
|
|
||||||
attrs, err := attributes.ParseV2Attributes(stringAttributes, nil)
|
|
||||||
if err != nil {
|
|
||||||
fatalOnErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return addWellKnownAttributes(attrs)
|
|
||||||
}
|
|
||||||
|
|
||||||
type wellKnownNodeAttrDesc struct {
|
|
||||||
explicit bool
|
|
||||||
defaultVal string
|
|
||||||
}
|
|
||||||
|
|
||||||
func listWellKnownAttrDesc() map[string]wellKnownNodeAttrDesc {
|
|
||||||
return map[string]wellKnownNodeAttrDesc{
|
|
||||||
netmap.AttrPrice: {defaultVal: strconv.FormatUint(defaultPrice, 10)},
|
|
||||||
netmap.AttrCapacity: {defaultVal: strconv.FormatUint(defaultCapacity, 10)},
|
|
||||||
netmap.AttrUNLOCODE: {explicit: true},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addWellKnownAttributes(attrs []netmap.NodeAttribute) []netmap.NodeAttribute {
|
|
||||||
mWellKnown := listWellKnownAttrDesc()
|
|
||||||
|
|
||||||
// check how user defined well-known attributes
|
|
||||||
for i := range attrs {
|
|
||||||
delete(mWellKnown, attrs[i].Key())
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, desc := range mWellKnown {
|
|
||||||
// check if required attribute is set
|
|
||||||
if desc.explicit {
|
|
||||||
fatalOnErr(fmt.Errorf("missing explicit value of required node attribute %s", key))
|
|
||||||
}
|
|
||||||
|
|
||||||
// set default value of the attribute
|
|
||||||
index := len(attrs)
|
|
||||||
attrs = append(attrs, netmap.NodeAttribute{})
|
|
||||||
attrs[index].SetKey(key)
|
|
||||||
attrs[index].SetValue(desc.defaultVal)
|
|
||||||
}
|
|
||||||
|
|
||||||
return attrs
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,21 +213,21 @@ func newCachedNetmapStorage(s netmap.State, v netmap.Source) netmap.Source {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *lruNetmapSource) GetNetMap(diff uint64) (*netmapSDK.Netmap, error) {
|
func (s *lruNetmapSource) GetNetMap(diff uint64) (*netmapSDK.NetMap, error) {
|
||||||
return s.getNetMapByEpoch(s.netState.CurrentEpoch() - diff)
|
return s.getNetMapByEpoch(s.netState.CurrentEpoch() - diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *lruNetmapSource) GetNetMapByEpoch(epoch uint64) (*netmapSDK.Netmap, error) {
|
func (s *lruNetmapSource) GetNetMapByEpoch(epoch uint64) (*netmapSDK.NetMap, error) {
|
||||||
return s.getNetMapByEpoch(epoch)
|
return s.getNetMapByEpoch(epoch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *lruNetmapSource) getNetMapByEpoch(epoch uint64) (*netmapSDK.Netmap, error) {
|
func (s *lruNetmapSource) getNetMapByEpoch(epoch uint64) (*netmapSDK.NetMap, error) {
|
||||||
val, err := s.cache.get(epoch)
|
val, err := s.cache.get(epoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return val.(*netmapSDK.Netmap), nil
|
return val.(*netmapSDK.NetMap), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *lruNetmapSource) Epoch() (uint64, error) {
|
func (s *lruNetmapSource) Epoch() (uint64, error) {
|
||||||
|
|
|
@ -480,15 +480,21 @@ func initObjectPool(cfg *config.Config) (pool cfgObjectRoutines) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cfg) LocalNodeInfo() (*netmapV2.NodeInfo, error) {
|
func (c *cfg) LocalNodeInfo() (*netmapV2.NodeInfo, error) {
|
||||||
ni := c.cfgNetmap.state.getNodeInfo()
|
var res netmapV2.NodeInfo
|
||||||
if ni != nil {
|
|
||||||
return ni.ToV2(), nil
|
ni, ok := c.cfgNetmap.state.getNodeInfo()
|
||||||
|
if ok {
|
||||||
|
ni.WriteToV2(&res)
|
||||||
|
} else {
|
||||||
|
c.cfgNodeInfo.localInfo.WriteToV2(&res)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.cfgNodeInfo.localInfo.ToV2(), nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleLocalNodeInfo rewrites local node info from netmap
|
// handleLocalNodeInfo rewrites local node info from the NeoFS network map.
|
||||||
|
// Called with nil when storage node is outside the NeoFS network map
|
||||||
|
// (before entering the network and after leaving it).
|
||||||
func (c *cfg) handleLocalNodeInfo(ni *netmap.NodeInfo) {
|
func (c *cfg) handleLocalNodeInfo(ni *netmap.NodeInfo) {
|
||||||
c.cfgNetmap.state.setNodeInfo(ni)
|
c.cfgNetmap.state.setNodeInfo(ni)
|
||||||
}
|
}
|
||||||
|
@ -496,10 +502,10 @@ func (c *cfg) handleLocalNodeInfo(ni *netmap.NodeInfo) {
|
||||||
// bootstrap sets local node's netmap status to "online".
|
// bootstrap sets local node's netmap status to "online".
|
||||||
func (c *cfg) bootstrap() error {
|
func (c *cfg) bootstrap() error {
|
||||||
ni := c.cfgNodeInfo.localInfo
|
ni := c.cfgNodeInfo.localInfo
|
||||||
ni.SetState(netmap.NodeStateOnline)
|
ni.SetOnline()
|
||||||
|
|
||||||
prm := nmClient.AddPeerPrm{}
|
prm := nmClient.AddPeerPrm{}
|
||||||
prm.SetNodeInfo(&ni)
|
prm.SetNodeInfo(ni)
|
||||||
|
|
||||||
return c.cfgNetmap.wrapper.AddPeer(prm)
|
return c.cfgNetmap.wrapper.AddPeer(prm)
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,7 +329,7 @@ type loadPlacementBuilder struct {
|
||||||
cnrSrc containerCore.Source
|
cnrSrc containerCore.Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loadPlacementBuilder) BuildPlacement(epoch uint64, cnr cid.ID) ([]netmap.Nodes, error) {
|
func (l *loadPlacementBuilder) BuildPlacement(epoch uint64, cnr cid.ID) ([][]netmap.NodeInfo, error) {
|
||||||
cnrNodes, nm, err := l.buildPlacement(epoch, cnr)
|
cnrNodes, nm, err := l.buildPlacement(epoch, cnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -341,7 +341,7 @@ func (l *loadPlacementBuilder) BuildPlacement(epoch uint64, cnr cid.ID) ([]netma
|
||||||
pivotPrefix + strconv.FormatUint(epoch, 10),
|
pivotPrefix + strconv.FormatUint(epoch, 10),
|
||||||
)
|
)
|
||||||
|
|
||||||
placement, err := nm.GetPlacementVectors(cnrNodes, pivot)
|
placement, err := nm.PlacementVectors(cnrNodes, pivot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not build placement vectors: %w", err)
|
return nil, fmt.Errorf("could not build placement vectors: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -349,12 +349,17 @@ func (l *loadPlacementBuilder) BuildPlacement(epoch uint64, cnr cid.ID) ([]netma
|
||||||
return placement, nil
|
return placement, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *loadPlacementBuilder) buildPlacement(epoch uint64, idCnr cid.ID) (netmap.ContainerNodes, *netmap.Netmap, error) {
|
func (l *loadPlacementBuilder) buildPlacement(epoch uint64, idCnr cid.ID) ([][]netmap.NodeInfo, *netmap.NetMap, error) {
|
||||||
cnr, err := l.cnrSrc.Get(idCnr)
|
cnr, err := l.cnrSrc.Get(idCnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
policy := cnr.PlacementPolicy()
|
||||||
|
if policy == nil {
|
||||||
|
return nil, nil, errors.New("missing placement policy in container")
|
||||||
|
}
|
||||||
|
|
||||||
nm, err := l.nmSrc.GetNetMapByEpoch(epoch)
|
nm, err := l.nmSrc.GetNetMapByEpoch(epoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("could not get network map: %w", err)
|
return nil, nil, fmt.Errorf("could not get network map: %w", err)
|
||||||
|
@ -363,7 +368,7 @@ func (l *loadPlacementBuilder) buildPlacement(epoch uint64, idCnr cid.ID) (netma
|
||||||
binCnr := make([]byte, sha256.Size)
|
binCnr := make([]byte, sha256.Size)
|
||||||
idCnr.Encode(binCnr)
|
idCnr.Encode(binCnr)
|
||||||
|
|
||||||
cnrNodes, err := nm.GetContainerNodes(cnr.PlacementPolicy(), binCnr)
|
cnrNodes, err := nm.ContainerNodes(*policy, binCnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("could not build container nodes: %w", err)
|
return nil, nil, fmt.Errorf("could not build container nodes: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -512,9 +517,9 @@ func (l *loadPlacementBuilder) isNodeFromContainerKey(epoch uint64, cnr cid.ID,
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, vector := range cnrNodes.Replicas() {
|
for i := range cnrNodes {
|
||||||
for _, node := range vector {
|
for j := range cnrNodes[i] {
|
||||||
if bytes.Equal(node.PublicKey(), key) {
|
if bytes.Equal(cnrNodes[i][j].PublicKey(), key) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
netmapV2 "github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
|
||||||
netmapGRPC "github.com/nspcc-dev/neofs-api-go/v2/netmap/grpc"
|
netmapGRPC "github.com/nspcc-dev/neofs-api-go/v2/netmap/grpc"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
|
||||||
nodeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/node"
|
nodeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/node"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/metrics"
|
"github.com/nspcc-dev/neofs-node/pkg/metrics"
|
||||||
|
@ -20,6 +18,7 @@ import (
|
||||||
netmapService "github.com/nspcc-dev/neofs-node/pkg/services/netmap"
|
netmapService "github.com/nspcc-dev/neofs-node/pkg/services/netmap"
|
||||||
netmapSDK "github.com/nspcc-dev/neofs-sdk-go/netmap"
|
netmapSDK "github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
|
subnetid "github.com/nspcc-dev/neofs-sdk-go/subnet/id"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/version"
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -53,16 +52,18 @@ func (s *networkState) setCurrentEpoch(v uint64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *networkState) setNodeInfo(ni *netmapSDK.NodeInfo) {
|
func (s *networkState) setNodeInfo(ni *netmapSDK.NodeInfo) {
|
||||||
s.nodeInfo.Store(ni)
|
ctrlNetSt := control.NetmapStatus_STATUS_UNDEFINED
|
||||||
|
|
||||||
var ctrlNetSt control.NetmapStatus
|
if ni != nil {
|
||||||
|
s.nodeInfo.Store(*ni)
|
||||||
|
|
||||||
switch ni.State() {
|
switch {
|
||||||
default:
|
case ni.IsOnline():
|
||||||
ctrlNetSt = control.NetmapStatus_STATUS_UNDEFINED
|
|
||||||
case netmapSDK.NodeStateOnline:
|
|
||||||
ctrlNetSt = control.NetmapStatus_ONLINE
|
ctrlNetSt = control.NetmapStatus_ONLINE
|
||||||
case netmapSDK.NodeStateOffline:
|
case ni.IsOffline():
|
||||||
|
ctrlNetSt = control.NetmapStatus_OFFLINE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
ctrlNetSt = control.NetmapStatus_OFFLINE
|
ctrlNetSt = control.NetmapStatus_OFFLINE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,27 +74,48 @@ func (s *networkState) controlNetmapStatus() control.NetmapStatus {
|
||||||
return s.controlNetStatus.Load().(control.NetmapStatus)
|
return s.controlNetStatus.Load().(control.NetmapStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *networkState) getNodeInfo() *netmapSDK.NodeInfo {
|
func (s *networkState) getNodeInfo() (res netmapSDK.NodeInfo, ok bool) {
|
||||||
return s.nodeInfo.Load().(*netmapSDK.NodeInfo)
|
v := s.nodeInfo.Load()
|
||||||
|
if v != nil {
|
||||||
|
res, ok = v.(netmapSDK.NodeInfo)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("unexpected value in atomic node info state: %T", v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeKeyFromNetmap(c *cfg) []byte {
|
func nodeKeyFromNetmap(c *cfg) []byte {
|
||||||
return c.cfgNetmap.state.getNodeInfo().PublicKey()
|
ni, ok := c.cfgNetmap.state.getNodeInfo()
|
||||||
|
if ok {
|
||||||
|
return ni.PublicKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cfg) iterateNetworkAddresses(f func(string) bool) {
|
func (c *cfg) iterateNetworkAddresses(f func(string) bool) {
|
||||||
c.cfgNetmap.state.getNodeInfo().IterateAddresses(f)
|
ni, ok := c.cfgNetmap.state.getNodeInfo()
|
||||||
|
if ok {
|
||||||
|
ni.IterateNetworkEndpoints(f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cfg) addressNum() int {
|
func (c *cfg) addressNum() int {
|
||||||
return c.cfgNetmap.state.getNodeInfo().NumberOfAddresses()
|
ni, ok := c.cfgNetmap.state.getNodeInfo()
|
||||||
|
if ok {
|
||||||
|
return ni.NumberOfNetworkEndpoints()
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func initNetmapService(c *cfg) {
|
func initNetmapService(c *cfg) {
|
||||||
network.WriteToNodeInfo(c.localAddr, &c.cfgNodeInfo.localInfo)
|
network.WriteToNodeInfo(c.localAddr, &c.cfgNodeInfo.localInfo)
|
||||||
c.cfgNodeInfo.localInfo.SetPublicKey(c.key.PublicKey().Bytes())
|
c.cfgNodeInfo.localInfo.SetPublicKey(c.key.PublicKey().Bytes())
|
||||||
c.cfgNodeInfo.localInfo.SetAttributes(parseAttributes(c.appCfg)...)
|
parseAttributes(c)
|
||||||
c.cfgNodeInfo.localInfo.SetState(netmapSDK.NodeStateOffline)
|
c.cfgNodeInfo.localInfo.SetOffline()
|
||||||
|
|
||||||
readSubnetCfg(c)
|
readSubnetCfg(c)
|
||||||
|
|
||||||
|
@ -113,7 +135,7 @@ func initNetmapService(c *cfg) {
|
||||||
&netInfo{
|
&netInfo{
|
||||||
netState: c.cfgNetmap.state,
|
netState: c.cfgNetmap.state,
|
||||||
magic: c.cfgMorph.client,
|
magic: c.cfgMorph.client,
|
||||||
netCfg: c.cfgNetmap.wrapper.IterateConfigParameters,
|
morphClientNetMap: c.cfgNetmap.wrapper,
|
||||||
msPerBlockRdr: c.cfgMorph.client.MsPerBlock,
|
msPerBlockRdr: c.cfgMorph.client.MsPerBlock,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -236,14 +258,25 @@ func initNetmapState(c *cfg) {
|
||||||
ni, err := c.netmapLocalNodeState(epoch)
|
ni, err := c.netmapLocalNodeState(epoch)
|
||||||
fatalOnErrDetails("could not init network state", err)
|
fatalOnErrDetails("could not init network state", err)
|
||||||
|
|
||||||
|
stateWord := "undefined"
|
||||||
|
|
||||||
|
if ni != nil {
|
||||||
|
switch {
|
||||||
|
case ni.IsOnline():
|
||||||
|
stateWord = "online"
|
||||||
|
case ni.IsOffline():
|
||||||
|
stateWord = "offline"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.log.Info("initial network state",
|
c.log.Info("initial network state",
|
||||||
zap.Uint64("epoch", epoch),
|
zap.Uint64("epoch", epoch),
|
||||||
zap.Stringer("state", ni.State()),
|
zap.String("state", stateWord),
|
||||||
)
|
)
|
||||||
|
|
||||||
c.cfgNetmap.state.setCurrentEpoch(epoch)
|
c.cfgNetmap.state.setCurrentEpoch(epoch)
|
||||||
c.cfgNetmap.startEpoch = epoch
|
c.cfgNetmap.startEpoch = epoch
|
||||||
c.cfgNetmap.state.setNodeInfo(ni)
|
c.handleLocalNodeInfo(ni)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cfg) netmapLocalNodeState(epoch uint64) (*netmapSDK.NodeInfo, error) {
|
func (c *cfg) netmapLocalNodeState(epoch uint64) (*netmapSDK.NodeInfo, error) {
|
||||||
|
@ -253,17 +286,14 @@ func (c *cfg) netmapLocalNodeState(epoch uint64) (*netmapSDK.NodeInfo, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.localNodeInfoFromNetmap(nm), nil
|
nmNodes := nm.Nodes()
|
||||||
}
|
for i := range nmNodes {
|
||||||
|
if bytes.Equal(nmNodes[i].PublicKey(), c.key.PublicKey().Bytes()) {
|
||||||
func (c *cfg) localNodeInfoFromNetmap(nm *netmapSDK.Netmap) *netmapSDK.NodeInfo {
|
return &nmNodes[i], nil
|
||||||
for _, n := range nm.Nodes {
|
|
||||||
if bytes.Equal(n.PublicKey(), c.key.PublicKey().Bytes()) {
|
|
||||||
return n.NodeInfo
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// addNewEpochNotificationHandler adds handler that will be executed synchronously
|
// addNewEpochNotificationHandler adds handler that will be executed synchronously
|
||||||
|
@ -309,18 +339,11 @@ func (c *cfg) SetNetmapStatus(st control.NetmapStatus) error {
|
||||||
return c.bootstrap()
|
return c.bootstrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiState netmapSDK.NodeState
|
|
||||||
|
|
||||||
if st == control.NetmapStatus_OFFLINE {
|
|
||||||
apiState = netmapSDK.NodeStateOffline
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cfgNetmap.reBoostrapTurnedOff.Store(true)
|
c.cfgNetmap.reBoostrapTurnedOff.Store(true)
|
||||||
|
|
||||||
prm := nmClient.UpdatePeerPrm{}
|
prm := nmClient.UpdatePeerPrm{}
|
||||||
|
|
||||||
prm.SetKey(c.key.PublicKey().Bytes())
|
prm.SetKey(c.key.PublicKey().Bytes())
|
||||||
prm.SetState(apiState)
|
|
||||||
|
|
||||||
return c.cfgNetmap.wrapper.UpdatePeerState(prm)
|
return c.cfgNetmap.wrapper.UpdatePeerState(prm)
|
||||||
}
|
}
|
||||||
|
@ -332,50 +355,49 @@ type netInfo struct {
|
||||||
MagicNumber() (uint64, error)
|
MagicNumber() (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
netCfg func(func(key, value []byte) error) error
|
morphClientNetMap *nmClient.Client
|
||||||
|
|
||||||
msPerBlockRdr func() (int64, error)
|
msPerBlockRdr func() (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *netInfo) Dump(ver *refs.Version) (*netmapV2.NetworkInfo, error) {
|
func (n *netInfo) Dump(ver version.Version) (*netmapSDK.NetworkInfo, error) {
|
||||||
magic, err := n.magic.MagicNumber()
|
magic, err := n.magic.MagicNumber()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ni := new(netmapV2.NetworkInfo)
|
var ni netmapSDK.NetworkInfo
|
||||||
ni.SetCurrentEpoch(n.netState.CurrentEpoch())
|
ni.SetCurrentEpoch(n.netState.CurrentEpoch())
|
||||||
ni.SetMagicNumber(magic)
|
ni.SetMagicNumber(magic)
|
||||||
|
|
||||||
if mjr := ver.GetMajor(); mjr > 2 || mjr == 2 && ver.GetMinor() > 9 {
|
netInfoMorph, err := n.morphClientNetMap.ReadNetworkConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read network configuration using netmap contract client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mjr := ver.Major(); mjr > 2 || mjr == 2 && ver.Minor() > 9 {
|
||||||
msPerBlock, err := n.msPerBlockRdr()
|
msPerBlock, err := n.msPerBlockRdr()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ms per block: %w", err)
|
return nil, fmt.Errorf("ms per block: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
ps []netmapV2.NetworkParameter
|
|
||||||
netCfg netmapV2.NetworkConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := n.netCfg(func(key, value []byte) error {
|
|
||||||
var p netmapV2.NetworkParameter
|
|
||||||
|
|
||||||
p.SetKey(key)
|
|
||||||
p.SetValue(value)
|
|
||||||
|
|
||||||
ps = append(ps, p)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return nil, fmt.Errorf("network config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
netCfg.SetParameters(ps...)
|
|
||||||
|
|
||||||
ni.SetNetworkConfig(&netCfg)
|
|
||||||
ni.SetMsPerBlock(msPerBlock)
|
ni.SetMsPerBlock(msPerBlock)
|
||||||
|
|
||||||
|
ni.SetMaxObjectSize(netInfoMorph.MaxObjectSize)
|
||||||
|
ni.SetStoragePrice(netInfoMorph.StoragePrice)
|
||||||
|
ni.SetAuditFee(netInfoMorph.AuditFee)
|
||||||
|
ni.SetEpochDuration(netInfoMorph.EpochDuration)
|
||||||
|
ni.SetContainerFee(netInfoMorph.ContainerFee)
|
||||||
|
ni.SetNamedContainerFee(netInfoMorph.ContainerAliasFee)
|
||||||
|
ni.SetNumberOfEigenTrustIterations(netInfoMorph.EigenTrustIterations)
|
||||||
|
ni.SetEigenTrustAlpha(netInfoMorph.EigenTrustAlpha)
|
||||||
|
ni.SetIRCandidateFee(netInfoMorph.IRCandidateFee)
|
||||||
|
ni.SetWithdrawalFee(netInfoMorph.WithdrawalFee)
|
||||||
|
|
||||||
|
for i := range netInfoMorph.Raw {
|
||||||
|
ni.SetRawNetworkParameter(netInfoMorph.Raw[i].Name, netInfoMorph.Raw[i].Value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ni, nil
|
return &ni, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -530,10 +530,12 @@ func (c *reputationClientConstructor) Get(info coreclient.NodeInfo) (coreclient.
|
||||||
if err == nil {
|
if err == nil {
|
||||||
key := info.PublicKey()
|
key := info.PublicKey()
|
||||||
|
|
||||||
for i := range nm.Nodes {
|
nmNodes := nm.Nodes()
|
||||||
if bytes.Equal(nm.Nodes[i].PublicKey(), key) {
|
|
||||||
|
for i := range nmNodes {
|
||||||
|
if bytes.Equal(nmNodes[i].PublicKey(), key) {
|
||||||
prm := truststorage.UpdatePrm{}
|
prm := truststorage.UpdatePrm{}
|
||||||
prm.SetPeer(reputation.PeerIDFromBytes(nm.Nodes[i].PublicKey()))
|
prm.SetPeer(reputation.PeerIDFromBytes(nmNodes[i].PublicKey()))
|
||||||
|
|
||||||
return &reputationClient{
|
return &reputationClient{
|
||||||
MultiAddressClient: cl.(coreclient.MultiAddressClient),
|
MultiAddressClient: cl.(coreclient.MultiAddressClient),
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (i InitialTrustSource) InitialTrust(reputation.PeerID) (reputation.TrustVal
|
||||||
return reputation.TrustZero, fmt.Errorf("failed to get NetMap: %w", err)
|
return reputation.TrustZero, fmt.Errorf("failed to get NetMap: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeCount := reputation.TrustValueFromFloat64(float64(len(nm.Nodes)))
|
nodeCount := reputation.TrustValueFromFloat64(float64(len(nm.Nodes())))
|
||||||
if nodeCount == 0 {
|
if nodeCount == 0 {
|
||||||
return reputation.TrustZero, ErrEmptyNetMap
|
return reputation.TrustZero, ErrEmptyNetMap
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,14 +66,15 @@ func (it *TrustIterator) Iterate(h reputation.TrustHandler) error {
|
||||||
// find out if local node is presented in netmap
|
// find out if local node is presented in netmap
|
||||||
localIndex := -1
|
localIndex := -1
|
||||||
|
|
||||||
for i := range nm.Nodes {
|
nmNodes := nm.Nodes()
|
||||||
if bytes.Equal(nm.Nodes[i].PublicKey(), it.storage.LocalKey) {
|
for i := range nmNodes {
|
||||||
|
if bytes.Equal(nmNodes[i].PublicKey(), it.storage.LocalKey) {
|
||||||
localIndex = i
|
localIndex = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ln := len(nm.Nodes)
|
ln := len(nmNodes)
|
||||||
if localIndex >= 0 && ln > 0 {
|
if localIndex >= 0 && ln > 0 {
|
||||||
ln--
|
ln--
|
||||||
}
|
}
|
||||||
|
@ -81,13 +82,13 @@ func (it *TrustIterator) Iterate(h reputation.TrustHandler) error {
|
||||||
// calculate Pj http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf Chapter 4.5.
|
// calculate Pj http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf Chapter 4.5.
|
||||||
p := reputation.TrustOne.Div(reputation.TrustValueFromInt(ln))
|
p := reputation.TrustOne.Div(reputation.TrustValueFromInt(ln))
|
||||||
|
|
||||||
for i := range nm.Nodes {
|
for i := range nmNodes {
|
||||||
if i == localIndex {
|
if i == localIndex {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
trust := reputation.Trust{}
|
trust := reputation.Trust{}
|
||||||
trust.SetPeer(reputation.PeerIDFromBytes(nm.Nodes[i].PublicKey()))
|
trust.SetPeer(reputation.PeerIDFromBytes(nmNodes[i].PublicKey()))
|
||||||
trust.SetValue(p)
|
trust.SetValue(p)
|
||||||
trust.SetTrustingPeer(reputation.PeerIDFromBytes(it.storage.LocalKey))
|
trust.SetTrustingPeer(reputation.PeerIDFromBytes(it.storage.LocalKey))
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -19,7 +19,7 @@ require (
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220601120906-3bec6657f5c5 // indirect
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220601120906-3bec6657f5c5 // indirect
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.12.2
|
github.com/nspcc-dev/neofs-api-go/v2 v2.12.2
|
||||||
github.com/nspcc-dev/neofs-contract v0.15.1
|
github.com/nspcc-dev/neofs-contract v0.15.1
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220615085207-eb3b99081235
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220616082321-e986f4780721
|
||||||
github.com/nspcc-dev/tzhash v1.5.2
|
github.com/nspcc-dev/tzhash v1.5.2
|
||||||
github.com/panjf2000/ants/v2 v2.4.0
|
github.com/panjf2000/ants/v2 v2.4.0
|
||||||
github.com/paulmach/orb v0.2.2
|
github.com/paulmach/orb v0.2.2
|
||||||
|
|
BIN
go.sum
BIN
go.sum
Binary file not shown.
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/test"
|
"github.com/nspcc-dev/neofs-node/pkg/util/test"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
netmaptest "github.com/nspcc-dev/neofs-sdk-go/netmap/test"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/version"
|
"github.com/nspcc-dev/neofs-sdk-go/version"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -17,8 +17,8 @@ func TestCheckFormat(t *testing.T) {
|
||||||
|
|
||||||
require.Error(t, CheckFormat(c))
|
require.Error(t, CheckFormat(c))
|
||||||
|
|
||||||
policy := netmap.NewPlacementPolicy()
|
policy := netmaptest.PlacementPolicy()
|
||||||
c.SetPlacementPolicy(policy)
|
c.SetPlacementPolicy(&policy)
|
||||||
|
|
||||||
require.Error(t, CheckFormat(c))
|
require.Error(t, CheckFormat(c))
|
||||||
|
|
||||||
|
|
31
pkg/core/netmap/nodes.go
Normal file
31
pkg/core/netmap/nodes.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package netmap
|
||||||
|
|
||||||
|
import "github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
|
|
||||||
|
// Node is a named type of netmap.NodeInfo which provides interface needed
|
||||||
|
// in the current repository. Node is expected to be used everywhere instead
|
||||||
|
// of direct usage of netmap.NodeInfo, so it represents a type mediator.
|
||||||
|
type Node netmap.NodeInfo
|
||||||
|
|
||||||
|
// PublicKey returns public key bound to the storage node.
|
||||||
|
//
|
||||||
|
// Return value MUST NOT be mutated, make a copy first.
|
||||||
|
func (x Node) PublicKey() []byte {
|
||||||
|
return (netmap.NodeInfo)(x).PublicKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IterateAddresses iterates over all announced network addresses
|
||||||
|
// and passes them into f. Handler MUST NOT be nil.
|
||||||
|
func (x Node) IterateAddresses(f func(string) bool) {
|
||||||
|
(netmap.NodeInfo)(x).IterateNetworkEndpoints(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumberOfAddresses returns number of announced network addresses.
|
||||||
|
func (x Node) NumberOfAddresses() int {
|
||||||
|
return (netmap.NodeInfo)(x).NumberOfNetworkEndpoints()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nodes is a named type of []netmap.NodeInfo which provides interface needed
|
||||||
|
// in the current repository. Nodes is expected to be used everywhere instead
|
||||||
|
// of direct usage of []netmap.NodeInfo, so it represents a type mediator.
|
||||||
|
type Nodes []netmap.NodeInfo
|
|
@ -16,7 +16,7 @@ type Source interface {
|
||||||
//
|
//
|
||||||
// Implementations must not retain the network map pointer and modify
|
// Implementations must not retain the network map pointer and modify
|
||||||
// the network map through it.
|
// the network map through it.
|
||||||
GetNetMap(diff uint64) (*netmap.Netmap, error)
|
GetNetMap(diff uint64) (*netmap.NetMap, error)
|
||||||
|
|
||||||
// GetNetMapByEpoch reads network map by the epoch number from the storage.
|
// GetNetMapByEpoch reads network map by the epoch number from the storage.
|
||||||
// It returns the pointer to the requested network map and any error encountered.
|
// It returns the pointer to the requested network map and any error encountered.
|
||||||
|
@ -25,7 +25,7 @@ type Source interface {
|
||||||
//
|
//
|
||||||
// Implementations must not retain the network map pointer and modify
|
// Implementations must not retain the network map pointer and modify
|
||||||
// the network map through it.
|
// the network map through it.
|
||||||
GetNetMapByEpoch(epoch uint64) (*netmap.Netmap, error)
|
GetNetMapByEpoch(epoch uint64) (*netmap.NetMap, error)
|
||||||
|
|
||||||
// Epoch reads the current epoch from the storage.
|
// Epoch reads the current epoch from the storage.
|
||||||
// It returns thw number of the current epoch and any error encountered.
|
// It returns thw number of the current epoch and any error encountered.
|
||||||
|
@ -35,11 +35,11 @@ type Source interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLatestNetworkMap requests and returns the latest network map from the storage.
|
// GetLatestNetworkMap requests and returns the latest network map from the storage.
|
||||||
func GetLatestNetworkMap(src Source) (*netmap.Netmap, error) {
|
func GetLatestNetworkMap(src Source) (*netmap.NetMap, error) {
|
||||||
return src.GetNetMap(0)
|
return src.GetNetMap(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPreviousNetworkMap requests and returns previous from the latest network map from the storage.
|
// GetPreviousNetworkMap requests and returns previous from the latest network map from the storage.
|
||||||
func GetPreviousNetworkMap(src Source) (*netmap.Netmap, error) {
|
func GetPreviousNetworkMap(src Source) (*netmap.NetMap, error) {
|
||||||
return src.GetNetMap(1)
|
return src.GetNetMap(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,9 @@ func (ap *Processor) processEmit() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ln := len(networkMap.Nodes)
|
nmNodes := networkMap.Nodes()
|
||||||
|
|
||||||
|
ln := len(nmNodes)
|
||||||
if ln == 0 {
|
if ln == 0 {
|
||||||
ap.log.Debug("empty network map, do not emit gas")
|
ap.log.Debug("empty network map, do not emit gas")
|
||||||
|
|
||||||
|
@ -57,8 +59,8 @@ func (ap *Processor) processEmit() {
|
||||||
|
|
||||||
gasPerNode := fixedn.Fixed8(ap.storageEmission / uint64(ln))
|
gasPerNode := fixedn.Fixed8(ap.storageEmission / uint64(ln))
|
||||||
|
|
||||||
for i := range networkMap.Nodes {
|
for i := range nmNodes {
|
||||||
keyBytes := networkMap.Nodes[i].PublicKey()
|
keyBytes := nmNodes[i].PublicKey()
|
||||||
|
|
||||||
key, err := keys.NewPublicKeyFromBytes(keyBytes, elliptic.P256())
|
key, err := keys.NewPublicKeyFromBytes(keyBytes, elliptic.P256())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -6,11 +6,12 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
|
||||||
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
|
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/audit"
|
"github.com/nspcc-dev/neofs-node/pkg/services/audit"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/rand"
|
"github.com/nspcc-dev/neofs-node/pkg/util/rand"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -59,10 +60,19 @@ func (ap *Processor) processStartAudit(epoch uint64) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
policy := cnr.PlacementPolicy()
|
||||||
|
if policy == nil {
|
||||||
|
log.Error("missing placement policy in container, ignore",
|
||||||
|
zap.Stringer("cid", containers[i]),
|
||||||
|
)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
containers[i].Encode(pivot)
|
containers[i].Encode(pivot)
|
||||||
|
|
||||||
// find all container nodes for current epoch
|
// find all container nodes for current epoch
|
||||||
nodes, err := nm.GetContainerNodes(cnr.PlacementPolicy(), pivot)
|
nodes, err := nm.ContainerNodes(*policy, pivot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("can't build placement for container, ignore",
|
log.Info("can't build placement for container, ignore",
|
||||||
zap.Stringer("cid", containers[i]),
|
zap.Stringer("cid", containers[i]),
|
||||||
|
@ -71,7 +81,7 @@ func (ap *Processor) processStartAudit(epoch uint64) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
n := nodes.Flatten()
|
n := placement.FlattenNodes(nodes)
|
||||||
|
|
||||||
// shuffle nodes to ask a random one
|
// shuffle nodes to ask a random one
|
||||||
rand.Shuffle(len(n), func(i, j int) {
|
rand.Shuffle(len(n), func(i, j int) {
|
||||||
|
@ -110,7 +120,7 @@ func (ap *Processor) processStartAudit(epoch uint64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ap *Processor) findStorageGroups(cnr cid.ID, shuffled netmap.Nodes) []oid.ID {
|
func (ap *Processor) findStorageGroups(cnr cid.ID, shuffled netmapcore.Nodes) []oid.ID {
|
||||||
var sg []oid.ID
|
var sg []oid.ID
|
||||||
|
|
||||||
ln := len(shuffled)
|
ln := len(shuffled)
|
||||||
|
@ -130,7 +140,7 @@ func (ap *Processor) findStorageGroups(cnr cid.ID, shuffled netmap.Nodes) []oid.
|
||||||
zap.Int("total_tries", ln),
|
zap.Int("total_tries", ln),
|
||||||
)
|
)
|
||||||
|
|
||||||
err := clientcore.NodeInfoFromRawNetmapElement(&info, shuffled[i])
|
err := clientcore.NodeInfoFromRawNetmapElement(&info, netmapcore.Node(shuffled[i]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("parse client node info", zap.String("error", err.Error()))
|
log.Warn("parse client node info", zap.String("error", err.Error()))
|
||||||
|
|
||||||
|
|
|
@ -240,10 +240,15 @@ func checkSubnet(subCli *morphsubnet.Client, cnr *containerSDK.Container) error
|
||||||
return errors.New("missing owner")
|
return errors.New("missing owner")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
policy := cnr.PlacementPolicy()
|
||||||
|
if policy == nil {
|
||||||
|
return errors.New("missing placement policy")
|
||||||
|
}
|
||||||
|
|
||||||
prm := morphsubnet.UserAllowedPrm{}
|
prm := morphsubnet.UserAllowedPrm{}
|
||||||
|
|
||||||
subID := cnr.PlacementPolicy().SubnetID()
|
subID := policy.Subnet()
|
||||||
if subID == nil || subnetid.IsZero(*subID) {
|
if subnetid.IsZero(subID) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +261,7 @@ func checkSubnet(subCli *morphsubnet.Client, cnr *containerSDK.Container) error
|
||||||
}
|
}
|
||||||
|
|
||||||
if !res.Allowed() {
|
if !res.Allowed() {
|
||||||
return fmt.Errorf("user is not allowed to create containers in %s subnetwork", subID)
|
return fmt.Errorf("user is not allowed to create containers in %v subnetwork", subID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -3,7 +3,6 @@ package netmap
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
|
@ -39,20 +38,19 @@ func newCleanupTable(enabled bool, threshold uint64) cleanupTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update cleanup table based on on-chain information about netmap.
|
// Update cleanup table based on on-chain information about netmap.
|
||||||
func (c *cleanupTable) update(snapshot *netmap.Netmap, now uint64) {
|
func (c *cleanupTable) update(snapshot netmap.NetMap, now uint64) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
|
nmNodes := snapshot.Nodes()
|
||||||
|
|
||||||
// replacing map is less memory efficient but faster
|
// replacing map is less memory efficient but faster
|
||||||
newMap := make(map[string]epochStampWithNodeInfo, len(snapshot.Nodes))
|
newMap := make(map[string]epochStampWithNodeInfo, len(nmNodes))
|
||||||
|
|
||||||
for i := range snapshot.Nodes {
|
for i := range nmNodes {
|
||||||
binNodeInfo, err := snapshot.Nodes[i].Marshal()
|
binNodeInfo := nmNodes[i].Marshal()
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Errorf("could not marshal node info: %w", err)) // seems better than ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
keyString := hex.EncodeToString(snapshot.Nodes[i].PublicKey())
|
keyString := hex.EncodeToString(nmNodes[i].PublicKey())
|
||||||
|
|
||||||
access, ok := c.lastAccess[keyString]
|
access, ok := c.lastAccess[keyString]
|
||||||
if ok {
|
if ok {
|
||||||
|
|
|
@ -22,14 +22,13 @@ func TestCleanupTable(t *testing.T) {
|
||||||
newNodeInfo(genKey(t).PublicKey()),
|
newNodeInfo(genKey(t).PublicKey()),
|
||||||
}
|
}
|
||||||
|
|
||||||
networkMap, err := netmap.NewNetmap(netmap.NodesFromInfo(infos))
|
var networkMap netmap.NetMap
|
||||||
require.NoError(t, err)
|
networkMap.SetNodes(infos)
|
||||||
|
|
||||||
mapInfos := make(map[string][]byte)
|
mapInfos := make(map[string][]byte)
|
||||||
|
|
||||||
for i := range infos {
|
for i := range infos {
|
||||||
binNodeInfo, err := infos[i].Marshal()
|
binNodeInfo := infos[i].Marshal()
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
mapInfos[hex.EncodeToString(infos[i].PublicKey())] = binNodeInfo
|
mapInfos[hex.EncodeToString(infos[i].PublicKey())] = binNodeInfo
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,24 +30,12 @@ var errMissingRequiredAttr = errors.New("missing required attribute in DB record
|
||||||
//
|
//
|
||||||
// UN-LOCODE attribute remains untouched.
|
// UN-LOCODE attribute remains untouched.
|
||||||
func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error {
|
func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error {
|
||||||
mAttr := uniqueAttributes(n.Attributes())
|
attrLocode := n.LOCODE()
|
||||||
|
if attrLocode == "" {
|
||||||
// check if the derived attributes are presented
|
|
||||||
for attrKey := range v.mAttr {
|
|
||||||
if _, ok := mAttr[attrKey]; ok {
|
|
||||||
return fmt.Errorf("attribute derived from %s is presented: %s",
|
|
||||||
netmap.AttrUNLOCODE,
|
|
||||||
attrKey,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attrLocode, ok := mAttr[netmap.AttrUNLOCODE]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
lc, err := locode.FromString(attrLocode.Value())
|
lc, err := locode.FromString(attrLocode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid locode value: %w", err)
|
return fmt.Errorf("invalid locode value: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -57,41 +45,48 @@ func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error {
|
||||||
return fmt.Errorf("could not get locode record from DB: %w", err)
|
return fmt.Errorf("could not get locode record from DB: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for attrKey, attrDesc := range v.mAttr {
|
countryCode := record.CountryCode()
|
||||||
attrVal := attrDesc.converter(record)
|
if countryCode == nil {
|
||||||
if attrVal == "" {
|
|
||||||
if !attrDesc.optional {
|
|
||||||
return errMissingRequiredAttr
|
return errMissingRequiredAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
strCountryCode := countryCode.String()
|
||||||
|
if strCountryCode == "" {
|
||||||
|
return errMissingRequiredAttr
|
||||||
}
|
}
|
||||||
|
|
||||||
var a netmap.NodeAttribute
|
countryName := record.CountryName()
|
||||||
a.SetKey(attrKey)
|
if countryName == "" {
|
||||||
a.SetValue(attrVal)
|
return errMissingRequiredAttr
|
||||||
|
|
||||||
mAttr[attrKey] = a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
as := n.Attributes()
|
locationName := record.LocationName()
|
||||||
as = as[:0]
|
if locationName == "" {
|
||||||
|
return errMissingRequiredAttr
|
||||||
for _, attr := range mAttr {
|
|
||||||
as = append(as, attr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n.SetAttributes(as...)
|
continent := record.Continent()
|
||||||
|
if continent == nil {
|
||||||
|
return errMissingRequiredAttr
|
||||||
|
}
|
||||||
|
|
||||||
|
continentName := continent.String()
|
||||||
|
if continentName == "" {
|
||||||
|
return errMissingRequiredAttr
|
||||||
|
}
|
||||||
|
|
||||||
|
n.SetCountryCode(strCountryCode)
|
||||||
|
n.SetCountryName(countryName)
|
||||||
|
n.SetLocationName(locationName)
|
||||||
|
n.SetContinentName(continentName)
|
||||||
|
|
||||||
|
if subDivCode := record.SubDivCode(); subDivCode != "" {
|
||||||
|
n.SetSubdivisionCode(subDivCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if subDivName := record.SubDivName(); subDivName != "" {
|
||||||
|
n.SetSubdivisionName(subDivName)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func uniqueAttributes(as []netmap.NodeAttribute) map[string]netmap.NodeAttribute {
|
|
||||||
mAttr := make(map[string]netmap.NodeAttribute, len(as))
|
|
||||||
|
|
||||||
for _, attr := range as {
|
|
||||||
mAttr[attr.Key()] = attr
|
|
||||||
}
|
|
||||||
|
|
||||||
return mAttr
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,40 +34,21 @@ func (x db) Get(lc *locodestd.LOCODE) (locode.Record, error) {
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addAttrKV(n *netmap.NodeInfo, key, val string) {
|
|
||||||
var a netmap.NodeAttribute
|
|
||||||
|
|
||||||
a.SetKey(key)
|
|
||||||
a.SetValue(val)
|
|
||||||
|
|
||||||
n.SetAttributes(append(n.Attributes(), a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addLocodeAttrValue(n *netmap.NodeInfo, val string) {
|
func addLocodeAttrValue(n *netmap.NodeInfo, val string) {
|
||||||
addAttrKV(n, netmap.AttrUNLOCODE, val)
|
n.SetLOCODE(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addLocodeAttr(n *netmap.NodeInfo, lc locodestd.LOCODE) {
|
func addLocodeAttr(n *netmap.NodeInfo, lc locodestd.LOCODE) {
|
||||||
addLocodeAttrValue(n, fmt.Sprintf("%s %s", lc[0], lc[1]))
|
n.SetLOCODE(fmt.Sprintf("%s %s", lc[0], lc[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeInfoWithSomeAttrs() *netmap.NodeInfo {
|
func nodeInfoWithSomeAttrs() *netmap.NodeInfo {
|
||||||
n := netmap.NewNodeInfo()
|
var n netmap.NodeInfo
|
||||||
|
|
||||||
addAttrKV(n, "key1", "val1")
|
n.SetAttribute("key1", "val1")
|
||||||
addAttrKV(n, "key2", "val2")
|
n.SetAttribute("key2", "val2")
|
||||||
|
|
||||||
return n
|
return &n
|
||||||
}
|
|
||||||
|
|
||||||
func containsAttr(n *netmap.NodeInfo, key, val string) bool {
|
|
||||||
for _, a := range n.Attributes() {
|
|
||||||
if a.Key() == key && a.Value() == val {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidator_VerifyAndUpdate(t *testing.T) {
|
func TestValidator_VerifyAndUpdate(t *testing.T) {
|
||||||
|
@ -108,41 +89,11 @@ func TestValidator_VerifyAndUpdate(t *testing.T) {
|
||||||
|
|
||||||
validator := locode.New(p)
|
validator := locode.New(p)
|
||||||
|
|
||||||
t.Run("w/ derived attributes", func(t *testing.T) {
|
|
||||||
fn := func(withLocode bool) {
|
|
||||||
for _, derivedAttr := range []string{
|
|
||||||
netmap.AttrCountryCode,
|
|
||||||
netmap.AttrCountry,
|
|
||||||
netmap.AttrLocation,
|
|
||||||
netmap.AttrSubDivCode,
|
|
||||||
netmap.AttrSubDiv,
|
|
||||||
netmap.AttrContinent,
|
|
||||||
} {
|
|
||||||
n := nodeInfoWithSomeAttrs()
|
|
||||||
|
|
||||||
addAttrKV(n, derivedAttr, "some value")
|
|
||||||
|
|
||||||
if withLocode {
|
|
||||||
addLocodeAttr(n, r.LOCODE)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := validator.VerifyAndUpdate(n)
|
|
||||||
require.Error(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn(true)
|
|
||||||
fn(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("w/o locode", func(t *testing.T) {
|
t.Run("w/o locode", func(t *testing.T) {
|
||||||
n := nodeInfoWithSomeAttrs()
|
n := nodeInfoWithSomeAttrs()
|
||||||
|
|
||||||
attrs := n.Attributes()
|
|
||||||
|
|
||||||
err := validator.VerifyAndUpdate(n)
|
err := validator.VerifyAndUpdate(n)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, attrs, n.Attributes())
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("w/ locode", func(t *testing.T) {
|
t.Run("w/ locode", func(t *testing.T) {
|
||||||
|
@ -168,22 +119,14 @@ func TestValidator_VerifyAndUpdate(t *testing.T) {
|
||||||
|
|
||||||
addLocodeAttr(n, r.LOCODE)
|
addLocodeAttr(n, r.LOCODE)
|
||||||
|
|
||||||
attrs := n.Attributes()
|
|
||||||
|
|
||||||
err := validator.VerifyAndUpdate(n)
|
err := validator.VerifyAndUpdate(n)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
outAttrs := n.Attributes()
|
require.Equal(t, rec.CountryCode().String(), n.Attribute("CountryCode"))
|
||||||
|
require.Equal(t, rec.CountryName(), n.Attribute("Country"))
|
||||||
for _, a := range attrs {
|
require.Equal(t, rec.LocationName(), n.Attribute("Location"))
|
||||||
require.Contains(t, outAttrs, a)
|
require.Equal(t, rec.SubDivCode(), n.Attribute("SubDivCode"))
|
||||||
}
|
require.Equal(t, rec.SubDivName(), n.Attribute("SubDiv"))
|
||||||
|
require.Equal(t, rec.Continent().String(), n.Attribute("Continent"))
|
||||||
require.True(t, containsAttr(n, netmap.AttrCountryCode, rec.CountryCode().String()))
|
|
||||||
require.True(t, containsAttr(n, netmap.AttrCountry, rec.CountryName()))
|
|
||||||
require.True(t, containsAttr(n, netmap.AttrLocation, rec.LocationName()))
|
|
||||||
require.True(t, containsAttr(n, netmap.AttrSubDivCode, rec.SubDivCode()))
|
|
||||||
require.True(t, containsAttr(n, netmap.AttrSubDiv, rec.SubDivName()))
|
|
||||||
require.True(t, containsAttr(n, netmap.AttrContinent, rec.Continent().String()))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package locode
|
|
||||||
|
|
||||||
type attrDescriptor struct {
|
|
||||||
optional bool
|
|
||||||
converter func(Record) string
|
|
||||||
}
|
|
||||||
|
|
||||||
func countryCodeValue(r Record) (val string) {
|
|
||||||
return r.CountryCode().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func countryValue(r Record) string {
|
|
||||||
return r.CountryName()
|
|
||||||
}
|
|
||||||
|
|
||||||
func locationValue(r Record) string {
|
|
||||||
return r.LocationName()
|
|
||||||
}
|
|
||||||
|
|
||||||
func subDivCodeValue(r Record) string {
|
|
||||||
return r.SubDivCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
func subDivValue(r Record) string {
|
|
||||||
return r.SubDivName()
|
|
||||||
}
|
|
||||||
|
|
||||||
func continentValue(r Record) string {
|
|
||||||
return r.Continent().String()
|
|
||||||
}
|
|
|
@ -1,9 +1,5 @@
|
||||||
package locode
|
package locode
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Prm groups the required parameters of the Validator's constructor.
|
// Prm groups the required parameters of the Validator's constructor.
|
||||||
//
|
//
|
||||||
// All values must comply with the requirements imposed on them.
|
// All values must comply with the requirements imposed on them.
|
||||||
|
@ -26,8 +22,6 @@ type Prm struct {
|
||||||
// the Validator is immediately ready to work through API.
|
// the Validator is immediately ready to work through API.
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
db DB
|
db DB
|
||||||
|
|
||||||
mAttr map[string]attrDescriptor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new instance of the Validator.
|
// New creates a new instance of the Validator.
|
||||||
|
@ -39,16 +33,5 @@ type Validator struct {
|
||||||
func New(prm Prm) *Validator {
|
func New(prm Prm) *Validator {
|
||||||
return &Validator{
|
return &Validator{
|
||||||
db: prm.DB,
|
db: prm.DB,
|
||||||
mAttr: map[string]attrDescriptor{
|
|
||||||
netmap.AttrCountryCode: {converter: countryCodeValue},
|
|
||||||
netmap.AttrCountry: {converter: countryValue},
|
|
||||||
|
|
||||||
netmap.AttrLocation: {converter: locationValue},
|
|
||||||
|
|
||||||
netmap.AttrSubDivCode: {converter: subDivCodeValue, optional: true},
|
|
||||||
netmap.AttrSubDiv: {converter: subDivValue, optional: true},
|
|
||||||
|
|
||||||
netmap.AttrContinent: {converter: continentValue},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
// VerifyAndUpdate calls network.VerifyAddress.
|
// VerifyAndUpdate calls network.VerifyAddress.
|
||||||
func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error {
|
func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error {
|
||||||
err := network.VerifyMultiAddress(n)
|
err := network.VerifyMultiAddress(*n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not verify multiaddress: %w", err)
|
return fmt.Errorf("could not verify multiaddress: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ package netmap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
v2netmap "github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
||||||
netmapclient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
netmapclient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ func (np *Processor) processNetmapCleanupTick(ev netmapCleanupTick) {
|
||||||
prm := netmapclient.UpdatePeerPrm{}
|
prm := netmapclient.UpdatePeerPrm{}
|
||||||
|
|
||||||
prm.SetKey(key.Bytes())
|
prm.SetKey(key.Bytes())
|
||||||
prm.SetState(netmap.NodeStateOffline)
|
|
||||||
prm.SetHash(ev.TxHash())
|
prm.SetHash(ev.TxHash())
|
||||||
|
|
||||||
err = np.netmapClient.UpdatePeerState(prm)
|
err = np.netmapClient.UpdatePeerState(prm)
|
||||||
|
@ -45,7 +44,7 @@ func (np *Processor) processNetmapCleanupTick(ev netmapCleanupTick) {
|
||||||
uint32(ev.epoch),
|
uint32(ev.epoch),
|
||||||
nil,
|
nil,
|
||||||
methodUpdateStateNotary,
|
methodUpdateStateNotary,
|
||||||
int64(netmap.NodeStateOffline.ToV2()), key.Bytes(),
|
int64(v2netmap.Offline), key.Bytes(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (np *Processor) processNewEpoch(ev netmapEvent.NewEpoch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
np.netmapSnapshot.update(networkMap, epoch)
|
np.netmapSnapshot.update(*networkMap, epoch)
|
||||||
np.handleCleanupTick(netmapCleanupTick{epoch: epoch, txHash: ev.TxHash()})
|
np.handleCleanupTick(netmapCleanupTick{epoch: epoch, txHash: ev.TxHash()})
|
||||||
np.handleNewAudit(audit.NewAuditStartEvent(epoch))
|
np.handleNewAudit(audit.NewAuditStartEvent(epoch))
|
||||||
np.handleAuditSettlements(settlement.NewAuditEvent(epoch))
|
np.handleAuditSettlements(settlement.NewAuditEvent(epoch))
|
||||||
|
|
|
@ -3,8 +3,6 @@ package netmap
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
netmapclient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
netmapclient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
||||||
netmapEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/netmap"
|
netmapEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/netmap"
|
||||||
|
@ -36,7 +34,7 @@ func (np *Processor) processAddPeer(ev netmapEvent.AddPeer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmarshal node info
|
// unmarshal node info
|
||||||
nodeInfo := netmap.NewNodeInfo()
|
var nodeInfo netmap.NodeInfo
|
||||||
if err := nodeInfo.Unmarshal(ev.Node()); err != nil {
|
if err := nodeInfo.Unmarshal(ev.Node()); err != nil {
|
||||||
// it will be nice to have tx id at event structure to log it
|
// it will be nice to have tx id at event structure to log it
|
||||||
np.log.Warn("can't parse network map candidate")
|
np.log.Warn("can't parse network map candidate")
|
||||||
|
@ -44,7 +42,7 @@ func (np *Processor) processAddPeer(ev netmapEvent.AddPeer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate and update node info
|
// validate and update node info
|
||||||
err := np.nodeValidator.VerifyAndUpdate(nodeInfo)
|
err := np.nodeValidator.VerifyAndUpdate(&nodeInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
np.log.Warn("could not verify and update information about network map candidate",
|
np.log.Warn("could not verify and update information about network map candidate",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
|
@ -54,28 +52,10 @@ func (np *Processor) processAddPeer(ev netmapEvent.AddPeer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort attributes to make it consistent
|
// sort attributes to make it consistent
|
||||||
a := nodeInfo.Attributes()
|
nodeInfo.SortAttributes()
|
||||||
sort.Slice(a, func(i, j int) bool {
|
|
||||||
switch strings.Compare(a[i].Key(), a[j].Key()) {
|
|
||||||
case -1:
|
|
||||||
return true
|
|
||||||
case 1:
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return a[i].Value() < a[j].Value()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
nodeInfo.SetAttributes(a...)
|
|
||||||
|
|
||||||
// marshal updated node info structure
|
// marshal updated node info structure
|
||||||
nodeInfoBinary, err := nodeInfo.Marshal()
|
nodeInfoBinary := nodeInfo.Marshal()
|
||||||
if err != nil {
|
|
||||||
np.log.Warn("could not marshal updated network map candidate",
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
keyString := hex.EncodeToString(nodeInfo.PublicKey())
|
keyString := hex.EncodeToString(nodeInfo.PublicKey())
|
||||||
|
|
||||||
|
@ -121,15 +101,6 @@ func (np *Processor) processUpdatePeer(ev netmapEvent.UpdatePeer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// better use unified enum from neofs-api-go/v2/netmap package
|
|
||||||
if ev.Status() != netmap.NodeStateOffline {
|
|
||||||
np.log.Warn("node proposes unknown state",
|
|
||||||
zap.String("key", hex.EncodeToString(ev.PublicKey().Bytes())),
|
|
||||||
zap.Stringer("status", ev.Status()),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// flag node to remove from local view, so it can be re-bootstrapped
|
// flag node to remove from local view, so it can be re-bootstrapped
|
||||||
// again before new epoch will tick
|
// again before new epoch will tick
|
||||||
np.netmapSnapshot.flag(hex.EncodeToString(ev.PublicKey().Bytes()))
|
np.netmapSnapshot.flag(hex.EncodeToString(ev.PublicKey().Bytes()))
|
||||||
|
@ -141,7 +112,9 @@ func (np *Processor) processUpdatePeer(ev netmapEvent.UpdatePeer) {
|
||||||
} else {
|
} else {
|
||||||
prm := netmapclient.UpdatePeerPrm{}
|
prm := netmapclient.UpdatePeerPrm{}
|
||||||
|
|
||||||
prm.SetState(ev.Status())
|
if ev.Online() {
|
||||||
|
prm.SetOnline()
|
||||||
|
}
|
||||||
prm.SetKey(ev.PublicKey().Bytes())
|
prm.SetKey(ev.PublicKey().Bytes())
|
||||||
|
|
||||||
err = np.netmapClient.UpdatePeerState(prm)
|
err = np.netmapClient.UpdatePeerState(prm)
|
||||||
|
@ -181,12 +154,14 @@ func (np *Processor) processRemoveSubnetNode(ev subnetEvent.RemoveNode) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, node := range candidates.Nodes {
|
candidateNodes := candidates.Nodes()
|
||||||
if !bytes.Equal(node.NodeInfo.PublicKey(), ev.Node()) {
|
|
||||||
|
for i := range candidateNodes {
|
||||||
|
if !bytes.Equal(candidateNodes[i].PublicKey(), ev.Node()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = node.IterateSubnets(func(subNetID subnetid.ID) error {
|
err = candidateNodes[i].IterateSubnets(func(subNetID subnetid.ID) error {
|
||||||
if subNetID.Equals(subnetToRemoveFrom) {
|
if subNetID.Equals(subnetToRemoveFrom) {
|
||||||
return netmap.ErrRemoveSubnet
|
return netmap.ErrRemoveSubnet
|
||||||
}
|
}
|
||||||
|
@ -199,7 +174,6 @@ func (np *Processor) processRemoveSubnetNode(ev subnetEvent.RemoveNode) {
|
||||||
|
|
||||||
prm := netmapclient.UpdatePeerPrm{}
|
prm := netmapclient.UpdatePeerPrm{}
|
||||||
prm.SetKey(ev.Node())
|
prm.SetKey(ev.Node())
|
||||||
prm.SetState(netmap.NodeStateOffline)
|
|
||||||
prm.SetHash(ev.TxHash())
|
prm.SetHash(ev.TxHash())
|
||||||
|
|
||||||
err = np.netmapClient.UpdatePeerState(prm)
|
err = np.netmapClient.UpdatePeerState(prm)
|
||||||
|
@ -209,7 +183,7 @@ func (np *Processor) processRemoveSubnetNode(ev subnetEvent.RemoveNode) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
prm := netmapclient.AddPeerPrm{}
|
prm := netmapclient.AddPeerPrm{}
|
||||||
prm.SetNodeInfo(node.NodeInfo)
|
prm.SetNodeInfo(candidateNodes[i])
|
||||||
prm.SetHash(ev.TxHash())
|
prm.SetHash(ev.TxHash())
|
||||||
|
|
||||||
err = np.netmapClient.AddPeer(prm)
|
err = np.netmapClient.AddPeer(prm)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
|
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
neofsapiclient "github.com/nspcc-dev/neofs-node/pkg/innerring/internal/client"
|
neofsapiclient "github.com/nspcc-dev/neofs-node/pkg/innerring/internal/client"
|
||||||
auditproc "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/audit"
|
auditproc "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/audit"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/cache"
|
"github.com/nspcc-dev/neofs-node/pkg/network/cache"
|
||||||
|
@ -69,7 +70,7 @@ func (c *ClientCache) GetSG(task *audit.Task, id oid.ID) (*storagegroup.StorageG
|
||||||
return c.getSG(task.AuditContext(), sgAddress, task.NetworkMap(), task.ContainerNodes())
|
return c.getSG(task.AuditContext(), sgAddress, task.NetworkMap(), task.ContainerNodes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClientCache) getSG(ctx context.Context, addr oid.Address, nm *netmap.Netmap, cn netmap.ContainerNodes) (*storagegroup.StorageGroup, error) {
|
func (c *ClientCache) getSG(ctx context.Context, addr oid.Address, nm *netmap.NetMap, cn [][]netmap.NodeInfo) (*storagegroup.StorageGroup, error) {
|
||||||
obj := addr.Object()
|
obj := addr.Object()
|
||||||
|
|
||||||
nodes, err := placement.BuildObjectPlacement(nm, cn, &obj)
|
nodes, err := placement.BuildObjectPlacement(nm, cn, &obj)
|
||||||
|
@ -80,7 +81,7 @@ func (c *ClientCache) getSG(ctx context.Context, addr oid.Address, nm *netmap.Ne
|
||||||
var info clientcore.NodeInfo
|
var info clientcore.NodeInfo
|
||||||
|
|
||||||
for _, node := range placement.FlattenNodes(nodes) {
|
for _, node := range placement.FlattenNodes(nodes) {
|
||||||
err := clientcore.NodeInfoFromRawNetmapElement(&info, node)
|
err := clientcore.NodeInfoFromRawNetmapElement(&info, netmapcore.Node(node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse client node info: %w", err)
|
return nil, fmt.Errorf("parse client node info: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -124,14 +125,14 @@ func (c *ClientCache) getSG(ctx context.Context, addr oid.Address, nm *netmap.Ne
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeader requests node from the container under audit to return object header by id.
|
// GetHeader requests node from the container under audit to return object header by id.
|
||||||
func (c *ClientCache) GetHeader(task *audit.Task, node *netmap.Node, id oid.ID, relay bool) (*object.Object, error) {
|
func (c *ClientCache) GetHeader(task *audit.Task, node netmap.NodeInfo, id oid.ID, relay bool) (*object.Object, error) {
|
||||||
var objAddress oid.Address
|
var objAddress oid.Address
|
||||||
objAddress.SetContainer(task.ContainerID())
|
objAddress.SetContainer(task.ContainerID())
|
||||||
objAddress.SetObject(id)
|
objAddress.SetObject(id)
|
||||||
|
|
||||||
var info clientcore.NodeInfo
|
var info clientcore.NodeInfo
|
||||||
|
|
||||||
err := clientcore.NodeInfoFromRawNetmapElement(&info, node)
|
err := clientcore.NodeInfoFromRawNetmapElement(&info, netmapcore.Node(node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse client node info: %w", err)
|
return nil, fmt.Errorf("parse client node info: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -162,14 +163,14 @@ func (c *ClientCache) GetHeader(task *audit.Task, node *netmap.Node, id oid.ID,
|
||||||
|
|
||||||
// GetRangeHash requests node from the container under audit to return Tillich-Zemor hash of the
|
// GetRangeHash requests node from the container under audit to return Tillich-Zemor hash of the
|
||||||
// payload range of the object with specified identifier.
|
// payload range of the object with specified identifier.
|
||||||
func (c *ClientCache) GetRangeHash(task *audit.Task, node *netmap.Node, id oid.ID, rng *object.Range) ([]byte, error) {
|
func (c *ClientCache) GetRangeHash(task *audit.Task, node netmap.NodeInfo, id oid.ID, rng *object.Range) ([]byte, error) {
|
||||||
var objAddress oid.Address
|
var objAddress oid.Address
|
||||||
objAddress.SetContainer(task.ContainerID())
|
objAddress.SetContainer(task.ContainerID())
|
||||||
objAddress.SetObject(id)
|
objAddress.SetObject(id)
|
||||||
|
|
||||||
var info clientcore.NodeInfo
|
var info clientcore.NodeInfo
|
||||||
|
|
||||||
err := clientcore.NodeInfoFromRawNetmapElement(&info, node)
|
err := clientcore.NodeInfoFromRawNetmapElement(&info, netmapcore.Node(node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse client node info: %w", err)
|
return nil, fmt.Errorf("parse client node info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ import (
|
||||||
auditClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/audit"
|
auditClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/audit"
|
||||||
balanceClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance"
|
balanceClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance"
|
||||||
containerClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
containerClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||||
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
||||||
auditAPI "github.com/nspcc-dev/neofs-sdk-go/audit"
|
auditAPI "github.com/nspcc-dev/neofs-sdk-go/audit"
|
||||||
containerAPI "github.com/nspcc-dev/neofs-sdk-go/container"
|
containerAPI "github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
|
@ -75,7 +77,7 @@ type auditSettlementCalculator audit.Calculator
|
||||||
type containerWrapper containerAPI.Container
|
type containerWrapper containerAPI.Container
|
||||||
|
|
||||||
type nodeInfoWrapper struct {
|
type nodeInfoWrapper struct {
|
||||||
ni *netmapAPI.Node
|
ni netmapAPI.NodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type sgWrapper storagegroup.StorageGroup
|
type sgWrapper storagegroup.StorageGroup
|
||||||
|
@ -89,7 +91,7 @@ func (n nodeInfoWrapper) PublicKey() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n nodeInfoWrapper) Price() *big.Int {
|
func (n nodeInfoWrapper) Price() *big.Int {
|
||||||
return big.NewInt(int64(n.ni.Price))
|
return big.NewInt(int64(n.ni.Price()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *containerWrapper) Owner() user.ID {
|
func (c *containerWrapper) Owner() user.ID {
|
||||||
|
@ -125,9 +127,9 @@ func (s settlementDeps) ContainerInfo(cid cid.ID) (common.ContainerInfo, error)
|
||||||
return (*containerWrapper)(cnr), nil
|
return (*containerWrapper)(cnr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s settlementDeps) buildContainer(e uint64, cid cid.ID) (netmapAPI.ContainerNodes, *netmapAPI.Netmap, error) {
|
func (s settlementDeps) buildContainer(e uint64, cid cid.ID) ([][]netmapAPI.NodeInfo, *netmapAPI.NetMap, error) {
|
||||||
var (
|
var (
|
||||||
nm *netmapAPI.Netmap
|
nm *netmapAPI.NetMap
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -146,11 +148,16 @@ func (s settlementDeps) buildContainer(e uint64, cid cid.ID) (netmapAPI.Containe
|
||||||
return nil, nil, fmt.Errorf("could not get container from sidechain: %w", err)
|
return nil, nil, fmt.Errorf("could not get container from sidechain: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
policy := cnr.PlacementPolicy()
|
||||||
|
if policy == nil {
|
||||||
|
return nil, nil, errors.New("missing placement policy in container")
|
||||||
|
}
|
||||||
|
|
||||||
binCnr := make([]byte, sha256.Size)
|
binCnr := make([]byte, sha256.Size)
|
||||||
cid.Encode(binCnr)
|
cid.Encode(binCnr)
|
||||||
|
|
||||||
cn, err := nm.GetContainerNodes(
|
cn, err := nm.ContainerNodes(
|
||||||
cnr.PlacementPolicy(),
|
*policy,
|
||||||
binCnr, // may be replace pivot calculation to neofs-api-go
|
binCnr, // may be replace pivot calculation to neofs-api-go
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -166,12 +173,12 @@ func (s settlementDeps) ContainerNodes(e uint64, cid cid.ID) ([]common.NodeInfo,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := cn.Flatten()
|
ns := placement.FlattenNodes(cn)
|
||||||
res := make([]common.NodeInfo, 0, len(ns))
|
res := make([]common.NodeInfo, 0, len(ns))
|
||||||
|
|
||||||
for i := range ns {
|
for i := range ns {
|
||||||
res = append(res, &nodeInfoWrapper{
|
res = append(res, &nodeInfoWrapper{
|
||||||
ni: &ns[i],
|
ni: ns[i],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,19 +301,21 @@ func (s *Server) handleSubnetRemoval(e event.Event) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range candidates.Nodes {
|
candidateNodes := candidates.Nodes()
|
||||||
s.processCandidate(delEv.TxHash(), removedID, c)
|
|
||||||
|
for i := range candidateNodes {
|
||||||
|
s.processCandidate(delEv.TxHash(), removedID, candidateNodes[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) processCandidate(txHash neogoutil.Uint256, removedID subnetid.ID, c netmap.Node) {
|
func (s *Server) processCandidate(txHash neogoutil.Uint256, removedID subnetid.ID, c netmap.NodeInfo) {
|
||||||
removeSubnet := false
|
removeSubnet := false
|
||||||
log := s.log.With(
|
log := s.log.With(
|
||||||
zap.String("public_key", hex.EncodeToString(c.NodeInfo.PublicKey())),
|
zap.String("public_key", hex.EncodeToString(c.PublicKey())),
|
||||||
zap.String("removed_subnet", removedID.String()),
|
zap.String("removed_subnet", removedID.String()),
|
||||||
)
|
)
|
||||||
|
|
||||||
err := c.NodeInfo.IterateSubnets(func(id subnetid.ID) error {
|
err := c.IterateSubnets(func(id subnetid.ID) error {
|
||||||
if removedID.Equals(id) {
|
if removedID.Equals(id) {
|
||||||
removeSubnet = true
|
removeSubnet = true
|
||||||
return netmap.ErrRemoveSubnet
|
return netmap.ErrRemoveSubnet
|
||||||
|
@ -326,8 +328,7 @@ func (s *Server) processCandidate(txHash neogoutil.Uint256, removedID subnetid.I
|
||||||
log.Debug("removing node from netmap candidates")
|
log.Debug("removing node from netmap candidates")
|
||||||
|
|
||||||
var updateStatePrm netmapclient.UpdatePeerPrm
|
var updateStatePrm netmapclient.UpdatePeerPrm
|
||||||
updateStatePrm.SetState(netmap.NodeStateOffline)
|
updateStatePrm.SetKey(c.PublicKey())
|
||||||
updateStatePrm.SetKey(c.NodeInfo.PublicKey())
|
|
||||||
updateStatePrm.SetHash(txHash)
|
updateStatePrm.SetHash(txHash)
|
||||||
|
|
||||||
err = s.netmapClient.UpdatePeerState(updateStatePrm)
|
err = s.netmapClient.UpdatePeerState(updateStatePrm)
|
||||||
|
@ -346,7 +347,7 @@ func (s *Server) processCandidate(txHash neogoutil.Uint256, removedID subnetid.I
|
||||||
log.Debug("removing subnet from the node")
|
log.Debug("removing subnet from the node")
|
||||||
|
|
||||||
var addPeerPrm netmapclient.AddPeerPrm
|
var addPeerPrm netmapclient.AddPeerPrm
|
||||||
addPeerPrm.SetNodeInfo(c.NodeInfo)
|
addPeerPrm.SetNodeInfo(c)
|
||||||
addPeerPrm.SetHash(txHash)
|
addPeerPrm.SetHash(txHash)
|
||||||
|
|
||||||
err = s.netmapClient.AddPeer(addPeerPrm)
|
err = s.netmapClient.AddPeer(addPeerPrm)
|
||||||
|
|
|
@ -9,13 +9,13 @@ import (
|
||||||
|
|
||||||
// AddPeerPrm groups parameters of AddPeer operation.
|
// AddPeerPrm groups parameters of AddPeer operation.
|
||||||
type AddPeerPrm struct {
|
type AddPeerPrm struct {
|
||||||
nodeInfo *netmap.NodeInfo
|
nodeInfo netmap.NodeInfo
|
||||||
|
|
||||||
client.InvokePrmOptional
|
client.InvokePrmOptional
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNodeInfo sets new peer NodeInfo.
|
// SetNodeInfo sets new peer NodeInfo.
|
||||||
func (a *AddPeerPrm) SetNodeInfo(nodeInfo *netmap.NodeInfo) {
|
func (a *AddPeerPrm) SetNodeInfo(nodeInfo netmap.NodeInfo) {
|
||||||
a.nodeInfo = nodeInfo
|
a.nodeInfo = nodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,18 +31,9 @@ func (c *Client) AddPeer(p AddPeerPrm) error {
|
||||||
method += "IR"
|
method += "IR"
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.nodeInfo == nil {
|
|
||||||
return fmt.Errorf("nil node info (%s)", method)
|
|
||||||
}
|
|
||||||
|
|
||||||
rawNodeInfo, err := p.nodeInfo.Marshal()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("can't marshal node info (%s): %w", method, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
prm := client.InvokePrm{}
|
prm := client.InvokePrm{}
|
||||||
prm.SetMethod(method)
|
prm.SetMethod(method)
|
||||||
prm.SetArgs(rawNodeInfo)
|
prm.SetArgs(p.nodeInfo.Marshal())
|
||||||
prm.InvokePrmOptional = p.InvokePrmOptional
|
prm.InvokePrmOptional = p.InvokePrmOptional
|
||||||
|
|
||||||
if err := c.client.Invoke(prm); err != nil {
|
if err := c.client.Invoke(prm); err != nil {
|
||||||
|
|
|
@ -185,85 +185,112 @@ func (c *Client) SetConfig(p SetConfigPrm) error {
|
||||||
return c.client.Invoke(prm)
|
return c.client.Invoke(prm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IterateConfigParameters iterates over configuration parameters stored in Netmap contract and passes them to f.
|
// RawNetworkParameter is a NeoFS network parameter which is transmitted but
|
||||||
//
|
// not interpreted by the NeoFS API protocol.
|
||||||
// Returns f's errors directly.
|
type RawNetworkParameter struct {
|
||||||
func (c *Client) IterateConfigParameters(f func(key, value []byte) error) error {
|
// Name of the parameter.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Raw parameter value.
|
||||||
|
Value []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkConfiguration represents NeoFS network configuration stored
|
||||||
|
// in the NeoFS Sidechain.
|
||||||
|
type NetworkConfiguration struct {
|
||||||
|
MaxObjectSize uint64
|
||||||
|
|
||||||
|
StoragePrice uint64
|
||||||
|
|
||||||
|
AuditFee uint64
|
||||||
|
|
||||||
|
EpochDuration uint64
|
||||||
|
|
||||||
|
ContainerFee uint64
|
||||||
|
|
||||||
|
ContainerAliasFee uint64
|
||||||
|
|
||||||
|
EigenTrustIterations uint64
|
||||||
|
|
||||||
|
EigenTrustAlpha float64
|
||||||
|
|
||||||
|
IRCandidateFee uint64
|
||||||
|
|
||||||
|
WithdrawalFee uint64
|
||||||
|
|
||||||
|
Raw []RawNetworkParameter
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadNetworkConfiguration reads NetworkConfiguration from the NeoFS Sidechain.
|
||||||
|
func (c *Client) ReadNetworkConfiguration() (*NetworkConfiguration, error) {
|
||||||
prm := client.TestInvokePrm{}
|
prm := client.TestInvokePrm{}
|
||||||
prm.SetMethod(configListMethod)
|
prm.SetMethod(configListMethod)
|
||||||
|
|
||||||
items, err := c.client.TestInvoke(prm)
|
items, err := c.client.TestInvoke(prm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not perform test invocation (%s): %w",
|
return nil, fmt.Errorf("could not perform test invocation (%s): %w",
|
||||||
configListMethod, err)
|
configListMethod, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ln := len(items); ln != 1 {
|
if ln := len(items); ln != 1 {
|
||||||
return fmt.Errorf("unexpected stack item count (%s): %d", configListMethod, ln)
|
return nil, fmt.Errorf("unexpected stack item count (%s): %d", configListMethod, ln)
|
||||||
}
|
}
|
||||||
|
|
||||||
arr, err := client.ArrayFromStackItem(items[0])
|
arr, err := client.ArrayFromStackItem(items[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("record list (%s): %w", configListMethod, err)
|
return nil, fmt.Errorf("record list (%s): %w", configListMethod, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return iterateRecords(arr, func(key, value []byte) error {
|
m := make(map[string]struct{}, len(arr))
|
||||||
return f(key, value)
|
var res NetworkConfiguration
|
||||||
})
|
res.Raw = make([]RawNetworkParameter, 0, len(arr))
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigWriter is an interface of NeoFS network config writer.
|
err = iterateRecords(arr, func(name string, value []byte) error {
|
||||||
type ConfigWriter interface {
|
_, ok := m[name]
|
||||||
UnknownParameter(string, []byte)
|
if ok {
|
||||||
MaxObjectSize(uint64)
|
return fmt.Errorf("duplicated config name %s", name)
|
||||||
BasicIncomeRate(uint64)
|
}
|
||||||
AuditFee(uint64)
|
|
||||||
EpochDuration(uint64)
|
|
||||||
ContainerFee(uint64)
|
|
||||||
ContainerAliasFee(uint64)
|
|
||||||
EigenTrustIterations(uint64)
|
|
||||||
EigenTrustAlpha(float64)
|
|
||||||
InnerRingCandidateFee(uint64)
|
|
||||||
WithdrawFee(uint64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteConfig writes NeoFS network configuration received via iterator.
|
m[name] = struct{}{}
|
||||||
//
|
|
||||||
// Returns iterator's errors directly.
|
switch name {
|
||||||
func WriteConfig(dst ConfigWriter, iterator func(func(key, val []byte) error) error) error {
|
|
||||||
return iterator(func(key, val []byte) error {
|
|
||||||
switch k := string(key); k {
|
|
||||||
default:
|
default:
|
||||||
dst.UnknownParameter(k, val)
|
res.Raw = append(res.Raw, RawNetworkParameter{
|
||||||
|
Name: name,
|
||||||
|
Value: value,
|
||||||
|
})
|
||||||
case maxObjectSizeConfig:
|
case maxObjectSizeConfig:
|
||||||
dst.MaxObjectSize(bytesToUint64(val))
|
res.MaxObjectSize = bytesToUint64(value)
|
||||||
case basicIncomeRateConfig:
|
case basicIncomeRateConfig:
|
||||||
dst.BasicIncomeRate(bytesToUint64(val))
|
res.StoragePrice = bytesToUint64(value)
|
||||||
case auditFeeConfig:
|
case auditFeeConfig:
|
||||||
dst.AuditFee(bytesToUint64(val))
|
res.AuditFee = bytesToUint64(value)
|
||||||
case epochDurationConfig:
|
case epochDurationConfig:
|
||||||
dst.EpochDuration(bytesToUint64(val))
|
res.EpochDuration = bytesToUint64(value)
|
||||||
case containerFeeConfig:
|
case containerFeeConfig:
|
||||||
dst.ContainerFee(bytesToUint64(val))
|
res.ContainerFee = bytesToUint64(value)
|
||||||
case containerAliasFeeConfig:
|
case containerAliasFeeConfig:
|
||||||
dst.ContainerAliasFee(bytesToUint64(val))
|
res.ContainerAliasFee = bytesToUint64(value)
|
||||||
case etIterationsConfig:
|
case etIterationsConfig:
|
||||||
dst.EigenTrustIterations(bytesToUint64(val))
|
res.EigenTrustIterations = bytesToUint64(value)
|
||||||
case etAlphaConfig:
|
case etAlphaConfig:
|
||||||
v, err := strconv.ParseFloat(string(val), 64)
|
res.EigenTrustAlpha, err = strconv.ParseFloat(string(value), 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("prm %s: %v", etAlphaConfig, err)
|
return fmt.Errorf("invalid prm %s: %v", etAlphaConfig, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dst.EigenTrustAlpha(v)
|
|
||||||
case irCandidateFeeConfig:
|
case irCandidateFeeConfig:
|
||||||
dst.InnerRingCandidateFee(bytesToUint64(val))
|
res.IRCandidateFee = bytesToUint64(value)
|
||||||
case withdrawFeeConfig:
|
case withdrawFeeConfig:
|
||||||
dst.WithdrawFee(bytesToUint64(val))
|
res.WithdrawalFee = bytesToUint64(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bytesToUint64(val []byte) uint64 {
|
func bytesToUint64(val []byte) uint64 {
|
||||||
|
@ -307,7 +334,7 @@ func StringAssert(item stackitem.Item) (interface{}, error) {
|
||||||
// iterateRecords iterates over all config records and passes them to f.
|
// iterateRecords iterates over all config records and passes them to f.
|
||||||
//
|
//
|
||||||
// Returns f's errors directly.
|
// Returns f's errors directly.
|
||||||
func iterateRecords(arr []stackitem.Item, f func(key, value []byte) error) error {
|
func iterateRecords(arr []stackitem.Item, f func(key string, value []byte) error) error {
|
||||||
for i := range arr {
|
for i := range arr {
|
||||||
fields, err := client.ArrayFromStackItem(arr[i])
|
fields, err := client.ArrayFromStackItem(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -328,7 +355,7 @@ func iterateRecords(arr []stackitem.Item, f func(key, value []byte) error) error
|
||||||
return fmt.Errorf("record value: %w", err)
|
return fmt.Errorf("record value: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := f(k, v); err != nil {
|
if err := f(string(k), v); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// State is an enumeration of various states of the NeoFS node.
|
|
||||||
type State int64
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Undefined is unknown state.
|
|
||||||
Undefined State = iota
|
|
||||||
|
|
||||||
// Online is network unavailable state.
|
|
||||||
Online
|
|
||||||
|
|
||||||
// Offline is an active state in the network.
|
|
||||||
Offline
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
nodeInfoFixedPrmNumber = 1
|
nodeInfoFixedPrmNumber = 1
|
||||||
|
|
||||||
|
@ -31,7 +17,7 @@ const (
|
||||||
// GetNetMapByEpoch receives information list about storage nodes
|
// GetNetMapByEpoch receives information list about storage nodes
|
||||||
// through the Netmap contract call, composes network map
|
// through the Netmap contract call, composes network map
|
||||||
// from them and returns it. Returns snapshot of the specified epoch number.
|
// from them and returns it. Returns snapshot of the specified epoch number.
|
||||||
func (c *Client) GetNetMapByEpoch(epoch uint64) (*netmap.Netmap, error) {
|
func (c *Client) GetNetMapByEpoch(epoch uint64) (*netmap.NetMap, error) {
|
||||||
invokePrm := client.TestInvokePrm{}
|
invokePrm := client.TestInvokePrm{}
|
||||||
invokePrm.SetMethod(epochSnapshotMethod)
|
invokePrm.SetMethod(epochSnapshotMethod)
|
||||||
invokePrm.SetArgs(epoch)
|
invokePrm.SetArgs(epoch)
|
||||||
|
@ -48,7 +34,7 @@ func (c *Client) GetNetMapByEpoch(epoch uint64) (*netmap.Netmap, error) {
|
||||||
// GetCandidates receives information list about candidates
|
// GetCandidates receives information list about candidates
|
||||||
// for the next epoch network map through the Netmap contract
|
// for the next epoch network map through the Netmap contract
|
||||||
// call, composes network map from them and returns it.
|
// call, composes network map from them and returns it.
|
||||||
func (c *Client) GetCandidates() (*netmap.Netmap, error) {
|
func (c *Client) GetCandidates() (*netmap.NetMap, error) {
|
||||||
invokePrm := client.TestInvokePrm{}
|
invokePrm := client.TestInvokePrm{}
|
||||||
invokePrm.SetMethod(netMapCandidatesMethod)
|
invokePrm.SetMethod(netMapCandidatesMethod)
|
||||||
|
|
||||||
|
@ -62,7 +48,10 @@ func (c *Client) GetCandidates() (*netmap.Netmap, error) {
|
||||||
return nil, fmt.Errorf("could not parse contract response: %w", err)
|
return nil, fmt.Errorf("could not parse contract response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return netmap.NewNetmap(netmap.NodesFromInfo(candVals))
|
var nm netmap.NetMap
|
||||||
|
nm.SetNodes(candVals)
|
||||||
|
|
||||||
|
return &nm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetMap performs the test invoke of get network map
|
// NetMap performs the test invoke of get network map
|
||||||
|
@ -128,11 +117,9 @@ func stackItemToNodeInfo(prm stackitem.Item, res *netmap.NodeInfo) error {
|
||||||
|
|
||||||
switch state {
|
switch state {
|
||||||
case 1:
|
case 1:
|
||||||
res.SetState(netmap.NodeStateOnline)
|
res.SetOnline()
|
||||||
case 2:
|
case 2:
|
||||||
res.SetState(netmap.NodeStateOffline)
|
res.SetOffline()
|
||||||
default:
|
|
||||||
res.SetState(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -17,23 +17,29 @@ func Test_stackItemsToNodeInfos(t *testing.T) {
|
||||||
pub := make([]byte, 33)
|
pub := make([]byte, 33)
|
||||||
rand.Read(pub)
|
rand.Read(pub)
|
||||||
|
|
||||||
expected[i].SetState(netmap.NodeState(i % 3))
|
switch i % 3 {
|
||||||
|
case 1:
|
||||||
|
expected[i].SetOffline()
|
||||||
|
case 2:
|
||||||
|
expected[i].SetOnline()
|
||||||
|
}
|
||||||
|
|
||||||
expected[i].SetPublicKey(pub)
|
expected[i].SetPublicKey(pub)
|
||||||
|
|
||||||
var attr netmap.NodeAttribute
|
expected[i].SetAttribute("key", strconv.Itoa(i))
|
||||||
attr.SetKey("key")
|
|
||||||
attr.SetValue(strconv.Itoa(i))
|
|
||||||
expected[i].SetAttributes(attr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items := make([]stackitem.Item, 4)
|
items := make([]stackitem.Item, 4)
|
||||||
for i := range items {
|
for i := range items {
|
||||||
data, err := expected[i].Marshal()
|
data := expected[i].Marshal()
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
state := int64(expected[i].State())
|
var state int64
|
||||||
if state != 0 { // In contract online=1, offline=2, in API it is the other way.
|
|
||||||
state = 3 - state
|
switch {
|
||||||
|
case expected[i].IsOnline():
|
||||||
|
state = 1
|
||||||
|
case expected[i].IsOffline():
|
||||||
|
state = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
items[i] = stackitem.NewStruct([]stackitem.Item{
|
items[i] = stackitem.NewStruct([]stackitem.Item{
|
||||||
|
|
|
@ -12,17 +12,17 @@ import (
|
||||||
// through the Netmap contract call, composes network map
|
// through the Netmap contract call, composes network map
|
||||||
// from them and returns it. With diff == 0 returns current
|
// from them and returns it. With diff == 0 returns current
|
||||||
// network map, else return snapshot of previous network map.
|
// network map, else return snapshot of previous network map.
|
||||||
func (c *Client) GetNetMap(diff uint64) (*netmap.Netmap, error) {
|
func (c *Client) GetNetMap(diff uint64) (*netmap.NetMap, error) {
|
||||||
return c.getNetMap(diff)
|
return c.getNetMap(diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot returns current netmap node infos.
|
// Snapshot returns current netmap node infos.
|
||||||
// Consider using pkg/morph/client/netmap for this.
|
// Consider using pkg/morph/client/netmap for this.
|
||||||
func (c *Client) Snapshot() (*netmap.Netmap, error) {
|
func (c *Client) Snapshot() (*netmap.NetMap, error) {
|
||||||
return c.getNetMap(0)
|
return c.getNetMap(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) getNetMap(diff uint64) (*netmap.Netmap, error) {
|
func (c *Client) getNetMap(diff uint64) (*netmap.NetMap, error) {
|
||||||
prm := client.TestInvokePrm{}
|
prm := client.TestInvokePrm{}
|
||||||
prm.SetMethod(snapshotMethod)
|
prm.SetMethod(snapshotMethod)
|
||||||
prm.SetArgs(diff)
|
prm.SetArgs(diff)
|
||||||
|
@ -35,7 +35,7 @@ func (c *Client) getNetMap(diff uint64) (*netmap.Netmap, error) {
|
||||||
return unmarshalNetmap(res, snapshotMethod)
|
return unmarshalNetmap(res, snapshotMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalNetmap(items []stackitem.Item, method string) (*netmap.Netmap, error) {
|
func unmarshalNetmap(items []stackitem.Item, method string) (*netmap.NetMap, error) {
|
||||||
rawPeers, err := peersFromStackItems(items, method)
|
rawPeers, err := peersFromStackItems(items, method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -48,5 +48,8 @@ func unmarshalNetmap(items []stackitem.Item, method string) (*netmap.Netmap, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return netmap.NewNetmap(netmap.NodesFromInfo(result))
|
var nm netmap.NetMap
|
||||||
|
nm.SetNodes(result)
|
||||||
|
|
||||||
|
return &nm, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// UpdatePeerPrm groups parameters of UpdatePeerState operation.
|
// UpdatePeerPrm groups parameters of UpdatePeerState operation.
|
||||||
type UpdatePeerPrm struct {
|
type UpdatePeerPrm struct {
|
||||||
key []byte
|
key []byte
|
||||||
state netmap.NodeState
|
|
||||||
|
online bool
|
||||||
|
|
||||||
client.InvokePrmOptional
|
client.InvokePrmOptional
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ func (u *UpdatePeerPrm) SetKey(key []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetState sets node state.
|
// SetState sets node state.
|
||||||
func (u *UpdatePeerPrm) SetState(state netmap.NodeState) {
|
func (u *UpdatePeerPrm) SetOnline() {
|
||||||
u.state = state
|
u.online = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePeerState changes peer status through Netmap contract call.
|
// UpdatePeerState changes peer status through Netmap contract call.
|
||||||
|
@ -36,9 +36,14 @@ func (c *Client) UpdatePeerState(p UpdatePeerPrm) error {
|
||||||
method += "IR"
|
method += "IR"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state := 2
|
||||||
|
if p.online {
|
||||||
|
state = 1
|
||||||
|
}
|
||||||
|
|
||||||
prm := client.InvokePrm{}
|
prm := client.InvokePrm{}
|
||||||
prm.SetMethod(method)
|
prm.SetMethod(method)
|
||||||
prm.SetArgs(int64(p.state.ToV2()), p.key)
|
prm.SetArgs(int64(state), p.key)
|
||||||
prm.InvokePrmOptional = p.InvokePrmOptional
|
prm.InvokePrmOptional = p.InvokePrmOptional
|
||||||
|
|
||||||
if err := c.client.Invoke(prm); err != nil {
|
if err := c.client.Invoke(prm); err != nil {
|
||||||
|
|
|
@ -10,12 +10,12 @@ import (
|
||||||
v2netmap "github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
v2netmap "github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdatePeer struct {
|
type UpdatePeer struct {
|
||||||
publicKey *keys.PublicKey
|
publicKey *keys.PublicKey
|
||||||
status netmap.NodeState
|
|
||||||
|
online bool
|
||||||
|
|
||||||
// For notary notifications only.
|
// For notary notifications only.
|
||||||
// Contains raw transactions of notary request.
|
// Contains raw transactions of notary request.
|
||||||
|
@ -25,8 +25,8 @@ type UpdatePeer struct {
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
func (UpdatePeer) MorphEvent() {}
|
func (UpdatePeer) MorphEvent() {}
|
||||||
|
|
||||||
func (s UpdatePeer) Status() netmap.NodeState {
|
func (s UpdatePeer) Online() bool {
|
||||||
return s.status
|
return s.online
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s UpdatePeer) PublicKey() *keys.PublicKey {
|
func (s UpdatePeer) PublicKey() *keys.PublicKey {
|
||||||
|
@ -73,7 +73,13 @@ func ParseUpdatePeer(e *subscriptions.NotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not get node status: %w", err)
|
return nil, fmt.Errorf("could not get node status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.status = netmap.NodeStateFromV2(v2netmap.NodeState(st))
|
switch v2netmap.NodeState(st) {
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported node state %d", st)
|
||||||
|
case v2netmap.Offline:
|
||||||
|
case v2netmap.Online:
|
||||||
|
ev.online = true
|
||||||
|
}
|
||||||
|
|
||||||
return ev, nil
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,8 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
netmapv2 "github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
v2netmap "github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var errNilPubKey = errors.New("could not parse public key: public key is nil")
|
var errNilPubKey = errors.New("could not parse public key: public key is nil")
|
||||||
|
@ -27,10 +26,6 @@ func (s *UpdatePeer) setPublicKey(v []byte) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *UpdatePeer) setStatus(v uint32) {
|
|
||||||
s.status = netmap.NodeStateFromV2(netmapv2.NodeState(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// UpdateStateNotaryEvent is method name for netmap state updating
|
// UpdateStateNotaryEvent is method name for netmap state updating
|
||||||
// operations in `Netmap` contract. Is used as identificator for
|
// operations in `Netmap` contract. Is used as identificator for
|
||||||
|
@ -66,7 +61,13 @@ func ParseUpdatePeerNotary(ne event.NotaryEvent) (event.Event, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.setStatus(uint32(state))
|
switch v2netmap.NodeState(state) {
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported node state %d", err)
|
||||||
|
case v2netmap.Offline:
|
||||||
|
case v2netmap.Online:
|
||||||
|
ev.online = true
|
||||||
|
}
|
||||||
|
|
||||||
fieldNum++
|
fieldNum++
|
||||||
case fieldNum == expectedItemNumUpdatePeer:
|
case fieldNum == expectedItemNumUpdatePeer:
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,10 +14,7 @@ func TestParseUpdatePeer(t *testing.T) {
|
||||||
priv, err := keys.NewPrivateKey()
|
priv, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var (
|
publicKey := priv.PublicKey()
|
||||||
publicKey = priv.PublicKey()
|
|
||||||
state = netmap.NodeStateOffline
|
|
||||||
)
|
|
||||||
|
|
||||||
t.Run("wrong number of parameters", func(t *testing.T) {
|
t.Run("wrong number of parameters", func(t *testing.T) {
|
||||||
prms := []stackitem.Item{
|
prms := []stackitem.Item{
|
||||||
|
@ -48,14 +44,14 @@ func TestParseUpdatePeer(t *testing.T) {
|
||||||
|
|
||||||
t.Run("correct behavior", func(t *testing.T) {
|
t.Run("correct behavior", func(t *testing.T) {
|
||||||
ev, err := ParseUpdatePeer(createNotifyEventFromItems([]stackitem.Item{
|
ev, err := ParseUpdatePeer(createNotifyEventFromItems([]stackitem.Item{
|
||||||
stackitem.NewBigInteger(new(big.Int).SetInt64(int64(state.ToV2()))),
|
stackitem.NewBigInteger(new(big.Int).SetInt64(1)),
|
||||||
stackitem.NewByteArray(publicKey.Bytes()),
|
stackitem.NewByteArray(publicKey.Bytes()),
|
||||||
}))
|
}))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, UpdatePeer{
|
require.Equal(t, UpdatePeer{
|
||||||
publicKey: publicKey,
|
publicKey: publicKey,
|
||||||
status: state,
|
online: true,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,10 +132,11 @@ func WriteToNodeInfo(g AddressGroup, ni *netmap.NodeInfo) {
|
||||||
addrs := make([]string, 0, num)
|
addrs := make([]string, 0, num)
|
||||||
|
|
||||||
iterateAllAddresses(g, func(addr Address) {
|
iterateAllAddresses(g, func(addr Address) {
|
||||||
|
ni.SetNetworkEndpoints()
|
||||||
addrs = append(addrs, addr.String())
|
addrs = append(addrs, addr.String())
|
||||||
})
|
})
|
||||||
|
|
||||||
ni.SetAddresses(addrs...)
|
ni.SetNetworkEndpoints(addrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects checks if two AddressGroup have
|
// Intersects checks if two AddressGroup have
|
||||||
|
|
|
@ -30,6 +30,18 @@ var (
|
||||||
errUnsupportedPresentationProtocol = errors.New("unsupported presentation protocol in multiaddress")
|
errUnsupportedPresentationProtocol = errors.New("unsupported presentation protocol in multiaddress")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NodeEndpointsIterator is a wrapper over netmap.NodeInfo which implements
|
||||||
|
// MultiAddressIterator.
|
||||||
|
type NodeEndpointsIterator netmap.NodeInfo
|
||||||
|
|
||||||
|
func (x NodeEndpointsIterator) IterateAddresses(f func(string) bool) {
|
||||||
|
(netmap.NodeInfo)(x).IterateNetworkEndpoints(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x NodeEndpointsIterator) NumberOfAddresses() int {
|
||||||
|
return (netmap.NodeInfo)(x).NumberOfNetworkEndpoints()
|
||||||
|
}
|
||||||
|
|
||||||
// VerifyMultiAddress validates multiaddress of n.
|
// VerifyMultiAddress validates multiaddress of n.
|
||||||
//
|
//
|
||||||
// If n's address contains more than 3 protocols
|
// If n's address contains more than 3 protocols
|
||||||
|
@ -45,8 +57,8 @@ var (
|
||||||
// 2. tcp
|
// 2. tcp
|
||||||
// 3. tls(optional, may be absent)
|
// 3. tls(optional, may be absent)
|
||||||
//
|
//
|
||||||
func VerifyMultiAddress(ni *netmap.NodeInfo) error {
|
func VerifyMultiAddress(ni netmap.NodeInfo) error {
|
||||||
return iterateParsedAddresses(ni, checkProtocols)
|
return iterateParsedAddresses(NodeEndpointsIterator(ni), checkProtocols)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkProtocols(a Address) error {
|
func checkProtocols(a Address) error {
|
||||||
|
|
|
@ -55,10 +55,7 @@ func TestVerifyMultiAddress_Order(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func constructNodeInfo(address string) *netmap.NodeInfo {
|
func constructNodeInfo(address string) (ni netmap.NodeInfo) {
|
||||||
ni := new(netmap.NodeInfo)
|
ni.SetNetworkEndpoints(address)
|
||||||
|
|
||||||
ni.SetAddresses(address)
|
|
||||||
|
|
||||||
return ni
|
return ni
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ type Context struct {
|
||||||
sgMembersCache map[int][]oid.ID
|
sgMembersCache map[int][]oid.ID
|
||||||
|
|
||||||
placementMtx sync.Mutex
|
placementMtx sync.Mutex
|
||||||
placementCache map[string][]netmap.Nodes
|
placementCache map[string][][]netmap.NodeInfo
|
||||||
|
|
||||||
porRequests, porRetries atomic.Uint32
|
porRequests, porRetries atomic.Uint32
|
||||||
|
|
||||||
|
@ -51,11 +51,11 @@ type Context struct {
|
||||||
type pairMemberInfo struct {
|
type pairMemberInfo struct {
|
||||||
failedPDP, passedPDP bool // at least one
|
failedPDP, passedPDP bool // at least one
|
||||||
|
|
||||||
node *netmap.Node
|
node netmap.NodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type gamePair struct {
|
type gamePair struct {
|
||||||
n1, n2 *netmap.Node
|
n1, n2 netmap.NodeInfo
|
||||||
|
|
||||||
id oid.ID
|
id oid.ID
|
||||||
|
|
||||||
|
@ -88,11 +88,11 @@ type ContainerCommunicator interface {
|
||||||
GetSG(*audit.Task, oid.ID) (*storagegroup.StorageGroup, error)
|
GetSG(*audit.Task, oid.ID) (*storagegroup.StorageGroup, error)
|
||||||
|
|
||||||
// Must return object header from the container node.
|
// Must return object header from the container node.
|
||||||
GetHeader(*audit.Task, *netmap.Node, oid.ID, bool) (*object.Object, error)
|
GetHeader(*audit.Task, netmap.NodeInfo, oid.ID, bool) (*object.Object, error)
|
||||||
|
|
||||||
// Must return homomorphic Tillich-Zemor hash of payload range of the
|
// Must return homomorphic Tillich-Zemor hash of payload range of the
|
||||||
// object stored in container node.
|
// object stored in container node.
|
||||||
GetRangeHash(*audit.Task, *netmap.Node, oid.ID, *object.Range) ([]byte, error)
|
GetRangeHash(*audit.Task, netmap.NodeInfo, oid.ID, *object.Range) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContext creates, initializes and returns Context.
|
// NewContext creates, initializes and returns Context.
|
||||||
|
@ -160,9 +160,12 @@ func (c *Context) init() {
|
||||||
|
|
||||||
c.sgMembersCache = make(map[int][]oid.ID)
|
c.sgMembersCache = make(map[int][]oid.ID)
|
||||||
|
|
||||||
c.placementCache = make(map[string][]netmap.Nodes)
|
c.placementCache = make(map[string][][]netmap.NodeInfo)
|
||||||
|
|
||||||
c.cnrNodesNum = len(c.task.ContainerNodes().Flatten())
|
cnrVectors := c.task.ContainerNodes()
|
||||||
|
for i := range cnrVectors {
|
||||||
|
c.cnrNodesNum += len(cnrVectors[i])
|
||||||
|
}
|
||||||
|
|
||||||
c.pairedNodes = make(map[uint64]*pairMemberInfo)
|
c.pairedNodes = make(map[uint64]*pairMemberInfo)
|
||||||
|
|
||||||
|
@ -200,7 +203,7 @@ func (c *Context) writeReport() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) buildPlacement(id oid.ID) ([]netmap.Nodes, error) {
|
func (c *Context) buildPlacement(id oid.ID) ([][]netmap.NodeInfo, error) {
|
||||||
c.placementMtx.Lock()
|
c.placementMtx.Lock()
|
||||||
defer c.placementMtx.Unlock()
|
defer c.placementMtx.Unlock()
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ func (c *Context) splitPayload(id oid.ID) []uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) collectHashes(p *gamePair) {
|
func (c *Context) collectHashes(p *gamePair) {
|
||||||
fn := func(n *netmap.Node, rngs []*object.Range) [][]byte {
|
fn := func(n netmap.NodeInfo, rngs []*object.Range) [][]byte {
|
||||||
// Here we randomize the order a bit: the hypothesis is that this
|
// Here we randomize the order a bit: the hypothesis is that this
|
||||||
// makes it harder for an unscrupulous node to come up with a
|
// makes it harder for an unscrupulous node to come up with a
|
||||||
// reliable cheating strategy.
|
// reliable cheating strategy.
|
||||||
|
@ -176,7 +176,7 @@ func (c *Context) analyzeHashes(p *gamePair) {
|
||||||
c.passNodesPDP(p.n1, p.n2)
|
c.passNodesPDP(p.n1, p.n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) failNodesPDP(ns ...*netmap.Node) {
|
func (c *Context) failNodesPDP(ns ...netmap.NodeInfo) {
|
||||||
c.pairedMtx.Lock()
|
c.pairedMtx.Lock()
|
||||||
|
|
||||||
for i := range ns {
|
for i := range ns {
|
||||||
|
@ -186,7 +186,7 @@ func (c *Context) failNodesPDP(ns ...*netmap.Node) {
|
||||||
c.pairedMtx.Unlock()
|
c.pairedMtx.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) passNodesPDP(ns ...*netmap.Node) {
|
func (c *Context) passNodesPDP(ns ...netmap.NodeInfo) {
|
||||||
c.pairedMtx.Lock()
|
c.pairedMtx.Lock()
|
||||||
|
|
||||||
for i := range ns {
|
for i := range ns {
|
||||||
|
@ -200,18 +200,18 @@ func (c *Context) writePairsResult() {
|
||||||
var failCount, okCount int
|
var failCount, okCount int
|
||||||
|
|
||||||
c.iteratePairedNodes(
|
c.iteratePairedNodes(
|
||||||
func(*netmap.Node) { failCount++ },
|
func(netmap.NodeInfo) { failCount++ },
|
||||||
func(*netmap.Node) { okCount++ },
|
func(netmap.NodeInfo) { okCount++ },
|
||||||
)
|
)
|
||||||
|
|
||||||
failedNodes := make([][]byte, 0, failCount)
|
failedNodes := make([][]byte, 0, failCount)
|
||||||
passedNodes := make([][]byte, 0, okCount)
|
passedNodes := make([][]byte, 0, okCount)
|
||||||
|
|
||||||
c.iteratePairedNodes(
|
c.iteratePairedNodes(
|
||||||
func(n *netmap.Node) {
|
func(n netmap.NodeInfo) {
|
||||||
failedNodes = append(failedNodes, n.PublicKey())
|
failedNodes = append(failedNodes, n.PublicKey())
|
||||||
},
|
},
|
||||||
func(n *netmap.Node) {
|
func(n netmap.NodeInfo) {
|
||||||
passedNodes = append(passedNodes, n.PublicKey())
|
passedNodes = append(passedNodes, n.PublicKey())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -219,7 +219,7 @@ func (c *Context) writePairsResult() {
|
||||||
c.report.SetPDPResults(passedNodes, failedNodes)
|
c.report.SetPDPResults(passedNodes, failedNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) iteratePairedNodes(onFail, onPass func(*netmap.Node)) {
|
func (c *Context) iteratePairedNodes(onFail, onPass func(netmap.NodeInfo)) {
|
||||||
for _, pairedNode := range c.pairedNodes {
|
for _, pairedNode := range c.pairedNodes {
|
||||||
if pairedNode.failedPDP {
|
if pairedNode.failedPDP {
|
||||||
onFail(pairedNode.node)
|
onFail(pairedNode.node)
|
||||||
|
|
|
@ -23,12 +23,12 @@ func (c *Context) executePoP() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) buildCoverage() {
|
func (c *Context) buildCoverage() {
|
||||||
replicas := c.task.ContainerStructure().PlacementPolicy().Replicas()
|
policy := c.task.ContainerStructure().PlacementPolicy()
|
||||||
|
|
||||||
// select random member from another storage group
|
// select random member from another storage group
|
||||||
// and process all placement vectors
|
// and process all placement vectors
|
||||||
c.iterateSGMembersPlacementRand(func(id oid.ID, ind int, nodes netmap.Nodes) bool {
|
c.iterateSGMembersPlacementRand(func(id oid.ID, ind int, nodes []netmap.NodeInfo) bool {
|
||||||
c.processObjectPlacement(id, nodes, replicas[ind].Count())
|
c.processObjectPlacement(id, nodes, policy.ReplicaNumberByIndex(ind))
|
||||||
return c.containerCovered()
|
return c.containerCovered()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ func (c *Context) containerCovered() bool {
|
||||||
return c.cnrNodesNum <= len(c.pairedNodes)
|
return c.cnrNodesNum <= len(c.pairedNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) processObjectPlacement(id oid.ID, nodes netmap.Nodes, replicas uint32) {
|
func (c *Context) processObjectPlacement(id oid.ID, nodes []netmap.NodeInfo, replicas uint32) {
|
||||||
var (
|
var (
|
||||||
ok uint32
|
ok uint32
|
||||||
optimal bool
|
optimal bool
|
||||||
|
@ -50,7 +50,7 @@ func (c *Context) processObjectPlacement(id oid.ID, nodes netmap.Nodes, replicas
|
||||||
|
|
||||||
for i := 0; ok < replicas && i < len(nodes); i++ {
|
for i := 0; ok < replicas && i < len(nodes); i++ {
|
||||||
// try to get object header from node
|
// try to get object header from node
|
||||||
hdr, err := c.cnrCom.GetHeader(c.task, &nodes[i], id, false)
|
hdr, err := c.cnrCom.GetHeader(c.task, nodes[i], id, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.log.Debug("could not get object header from candidate",
|
c.log.Debug("could not get object header from candidate",
|
||||||
zap.Stringer("id", id),
|
zap.Stringer("id", id),
|
||||||
|
@ -95,14 +95,14 @@ func (c *Context) processObjectPlacement(id oid.ID, nodes netmap.Nodes, replicas
|
||||||
|
|
||||||
if unpairedCandidate1 >= 0 {
|
if unpairedCandidate1 >= 0 {
|
||||||
if unpairedCandidate2 >= 0 {
|
if unpairedCandidate2 >= 0 {
|
||||||
c.composePair(id, &nodes[unpairedCandidate1], &nodes[unpairedCandidate2])
|
c.composePair(id, nodes[unpairedCandidate1], nodes[unpairedCandidate2])
|
||||||
} else if pairedCandidate >= 0 {
|
} else if pairedCandidate >= 0 {
|
||||||
c.composePair(id, &nodes[unpairedCandidate1], &nodes[pairedCandidate])
|
c.composePair(id, nodes[unpairedCandidate1], nodes[pairedCandidate])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) composePair(id oid.ID, n1, n2 *netmap.Node) {
|
func (c *Context) composePair(id oid.ID, n1, n2 netmap.NodeInfo) {
|
||||||
c.pairs = append(c.pairs, gamePair{
|
c.pairs = append(c.pairs, gamePair{
|
||||||
n1: n1,
|
n1: n1,
|
||||||
n2: n2,
|
n2: n2,
|
||||||
|
@ -117,7 +117,7 @@ func (c *Context) composePair(id oid.ID, n1, n2 *netmap.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) iterateSGMembersPlacementRand(f func(oid.ID, int, netmap.Nodes) bool) {
|
func (c *Context) iterateSGMembersPlacementRand(f func(oid.ID, int, []netmap.NodeInfo) bool) {
|
||||||
// iterate over storage groups members for all storage groups (one by one)
|
// iterate over storage groups members for all storage groups (one by one)
|
||||||
// with randomly shuffled members
|
// with randomly shuffled members
|
||||||
c.iterateSGMembersRand(func(id oid.ID) bool {
|
c.iterateSGMembersRand(func(id oid.ID) bool {
|
||||||
|
|
|
@ -78,7 +78,7 @@ func (c *Context) checkStorageGroupPoR(ind int, sg oid.ID) {
|
||||||
accRetries++
|
accRetries++
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr, err := c.cnrCom.GetHeader(c.task, &flat[j], members[i], true)
|
hdr, err := c.cnrCom.GetHeader(c.task, flat[j], members[i], true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.log.Debug("can't head object",
|
c.log.Debug("can't head object",
|
||||||
zap.String("remote_node", hex.EncodeToString(flat[j].PublicKey())),
|
zap.String("remote_node", hex.EncodeToString(flat[j].PublicKey())),
|
||||||
|
|
|
@ -19,9 +19,9 @@ type Task struct {
|
||||||
|
|
||||||
cnr *container.Container
|
cnr *container.Container
|
||||||
|
|
||||||
nm *netmap.Netmap
|
nm *netmap.NetMap
|
||||||
|
|
||||||
cnrNodes netmap.ContainerNodes
|
cnrNodes [][]netmap.NodeInfo
|
||||||
|
|
||||||
sgList []oid.ID
|
sgList []oid.ID
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ func (t *Task) ContainerStructure() *container.Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithContainerNodes sets nodes in the container under audit.
|
// WithContainerNodes sets nodes in the container under audit.
|
||||||
func (t *Task) WithContainerNodes(cnrNodes netmap.ContainerNodes) *Task {
|
func (t *Task) WithContainerNodes(cnrNodes [][]netmap.NodeInfo) *Task {
|
||||||
if t != nil {
|
if t != nil {
|
||||||
t.cnrNodes = cnrNodes
|
t.cnrNodes = cnrNodes
|
||||||
}
|
}
|
||||||
|
@ -92,12 +92,12 @@ func (t *Task) WithContainerNodes(cnrNodes netmap.ContainerNodes) *Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkMap returns network map of audit epoch.
|
// NetworkMap returns network map of audit epoch.
|
||||||
func (t *Task) NetworkMap() *netmap.Netmap {
|
func (t *Task) NetworkMap() *netmap.NetMap {
|
||||||
return t.nm
|
return t.nm
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNetworkMap sets network map of audit epoch.
|
// WithNetworkMap sets network map of audit epoch.
|
||||||
func (t *Task) WithNetworkMap(nm *netmap.Netmap) *Task {
|
func (t *Task) WithNetworkMap(nm *netmap.NetMap) *Task {
|
||||||
if t != nil {
|
if t != nil {
|
||||||
t.nm = nm
|
t.nm = nm
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ func (t *Task) WithNetworkMap(nm *netmap.Netmap) *Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerNodes returns nodes in the container under audit.
|
// ContainerNodes returns nodes in the container under audit.
|
||||||
func (t *Task) ContainerNodes() netmap.ContainerNodes {
|
func (t *Task) ContainerNodes() [][]netmap.NodeInfo {
|
||||||
return t.cnrNodes
|
return t.cnrNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
loadroute "github.com/nspcc-dev/neofs-node/pkg/services/container/announcement/load/route"
|
loadroute "github.com/nspcc-dev/neofs-node/pkg/services/container/announcement/load/route"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
)
|
)
|
||||||
|
@ -37,14 +38,12 @@ func (b *Builder) NextStage(a container.UsedSpaceAnnouncement, passed []loadrout
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
target := placement[i][0]
|
if len(passed) == 1 && bytes.Equal(passed[0].PublicKey(), placement[i][0].PublicKey()) {
|
||||||
|
|
||||||
if len(passed) == 1 && bytes.Equal(passed[0].PublicKey(), target.PublicKey()) {
|
|
||||||
// add nil element so the announcement will be saved in local memory
|
// add nil element so the announcement will be saved in local memory
|
||||||
res = append(res, nil)
|
res = append(res, nil)
|
||||||
} else {
|
} else {
|
||||||
// add element with remote node to send announcement to
|
// add element with remote node to send announcement to
|
||||||
res = append(res, target)
|
res = append(res, netmapcore.Node(placement[i][0]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,5 +10,5 @@ type PlacementBuilder interface {
|
||||||
// BuildPlacement must compose and sort (according to a specific algorithm)
|
// BuildPlacement must compose and sort (according to a specific algorithm)
|
||||||
// storage nodes from the container by its identifier using network map
|
// storage nodes from the container by its identifier using network map
|
||||||
// of particular epoch.
|
// of particular epoch.
|
||||||
BuildPlacement(epoch uint64, cnr cid.ID) ([]netmap.Nodes, error)
|
BuildPlacement(epoch uint64, cnr cid.ID) ([][]netmap.NodeInfo, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ func (s *Server) NetmapSnapshot(ctx context.Context, req *control.NetmapSnapshot
|
||||||
|
|
||||||
nm := new(control.Netmap)
|
nm := new(control.Netmap)
|
||||||
nm.SetEpoch(epoch)
|
nm.SetEpoch(epoch)
|
||||||
nm.SetNodes(nodesFromAPI(apiNetMap.Nodes))
|
nm.SetNodes(nodesFromAPI(apiNetMap.Nodes()))
|
||||||
|
|
||||||
// create and fill response
|
// create and fill response
|
||||||
resp := new(control.NetmapSnapshotResponse)
|
resp := new(control.NetmapSnapshotResponse)
|
||||||
|
@ -47,20 +47,28 @@ func (s *Server) NetmapSnapshot(ctx context.Context, req *control.NetmapSnapshot
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodesFromAPI(apiNodes netmapAPI.Nodes) []*control.NodeInfo {
|
func nodesFromAPI(apiNodes []netmapAPI.NodeInfo) []*control.NodeInfo {
|
||||||
nodes := make([]*control.NodeInfo, 0, len(apiNodes))
|
nodes := make([]*control.NodeInfo, 0, len(apiNodes))
|
||||||
|
|
||||||
for _, apiNode := range apiNodes {
|
for i := range apiNodes {
|
||||||
node := new(control.NodeInfo)
|
node := new(control.NodeInfo)
|
||||||
node.SetPublicKey(apiNode.PublicKey())
|
node.SetPublicKey(apiNodes[i].PublicKey())
|
||||||
|
|
||||||
addrs := make([]string, 0, apiNode.NumberOfAddresses())
|
addrs := make([]string, 0, apiNodes[i].NumberOfNetworkEndpoints())
|
||||||
netmapAPI.IterateAllAddresses(apiNode.NodeInfo, func(s string) {
|
netmapAPI.IterateNetworkEndpoints(apiNodes[i], func(s string) {
|
||||||
addrs = append(addrs, s)
|
addrs = append(addrs, s)
|
||||||
})
|
})
|
||||||
node.SetAddresses(addrs)
|
node.SetAddresses(addrs)
|
||||||
node.SetAttributes(attributesFromAPI(apiNode.Attributes()))
|
node.SetAttributes(attributesFromAPI(apiNodes[i]))
|
||||||
node.SetState(stateFromAPI(apiNode.State()))
|
|
||||||
|
switch {
|
||||||
|
default:
|
||||||
|
node.SetState(control.NetmapStatus_STATUS_UNDEFINED)
|
||||||
|
case apiNodes[i].IsOnline():
|
||||||
|
node.SetState(control.NetmapStatus_ONLINE)
|
||||||
|
case apiNodes[i].IsOffline():
|
||||||
|
node.SetState(control.NetmapStatus_OFFLINE)
|
||||||
|
}
|
||||||
|
|
||||||
nodes = append(nodes, node)
|
nodes = append(nodes, node)
|
||||||
}
|
}
|
||||||
|
@ -68,36 +76,16 @@ func nodesFromAPI(apiNodes netmapAPI.Nodes) []*control.NodeInfo {
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func stateFromAPI(s netmapAPI.NodeState) control.NetmapStatus {
|
func attributesFromAPI(apiNode netmapAPI.NodeInfo) []*control.NodeInfo_Attribute {
|
||||||
switch s {
|
attrs := make([]*control.NodeInfo_Attribute, 0, apiNode.NumberOfAttributes())
|
||||||
default:
|
|
||||||
return control.NetmapStatus_STATUS_UNDEFINED
|
|
||||||
case netmapAPI.NodeStateOffline:
|
|
||||||
return control.NetmapStatus_OFFLINE
|
|
||||||
case netmapAPI.NodeStateOnline:
|
|
||||||
return control.NetmapStatus_ONLINE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func attributesFromAPI(apiAttrs []netmapAPI.NodeAttribute) []*control.NodeInfo_Attribute {
|
apiNode.IterateAttributes(func(key, value string) {
|
||||||
attrs := make([]*control.NodeInfo_Attribute, 0, len(apiAttrs))
|
|
||||||
|
|
||||||
for _, apiAttr := range apiAttrs {
|
|
||||||
a := new(control.NodeInfo_Attribute)
|
a := new(control.NodeInfo_Attribute)
|
||||||
a.SetKey(apiAttr.Key())
|
a.SetKey(key)
|
||||||
a.SetValue(apiAttr.Value())
|
a.SetValue(value)
|
||||||
|
|
||||||
apiParents := apiAttr.ParentKeys()
|
|
||||||
parents := make([]string, 0, len(apiParents))
|
|
||||||
|
|
||||||
for i := range apiParents {
|
|
||||||
parents = append(parents, apiParents[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
a.SetParents(parents)
|
|
||||||
|
|
||||||
attrs = append(attrs, a)
|
attrs = append(attrs, a)
|
||||||
}
|
})
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
"github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/version"
|
"github.com/nspcc-dev/neofs-node/pkg/core/version"
|
||||||
|
netmapSDK "github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
versionsdk "github.com/nspcc-dev/neofs-sdk-go/version"
|
versionsdk "github.com/nspcc-dev/neofs-sdk-go/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ type NetworkInfo interface {
|
||||||
// Must return recent network information in NeoFS API v2 NetworkInfo structure.
|
// Must return recent network information in NeoFS API v2 NetworkInfo structure.
|
||||||
//
|
//
|
||||||
// If protocol version is <=2.9, MillisecondsPerBlock and network config should be unset.
|
// If protocol version is <=2.9, MillisecondsPerBlock and network config should be unset.
|
||||||
Dump(*refs.Version) (*netmap.NetworkInfo, error)
|
Dump(versionsdk.Version) (*netmapSDK.NetworkInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewExecutionService(s NodeState, v versionsdk.Version, netInfo NetworkInfo) Server {
|
func NewExecutionService(s NodeState, v versionsdk.Version, netInfo NetworkInfo) Server {
|
||||||
|
@ -93,13 +94,24 @@ func (s *executorSvc) LocalNodeInfo(
|
||||||
func (s *executorSvc) NetworkInfo(
|
func (s *executorSvc) NetworkInfo(
|
||||||
_ context.Context,
|
_ context.Context,
|
||||||
req *netmap.NetworkInfoRequest) (*netmap.NetworkInfoResponse, error) {
|
req *netmap.NetworkInfoRequest) (*netmap.NetworkInfoResponse, error) {
|
||||||
ni, err := s.netInfo.Dump(req.GetMetaHeader().GetVersion())
|
verV2 := req.GetMetaHeader().GetVersion()
|
||||||
|
if verV2 == nil {
|
||||||
|
return nil, errors.New("missing protocol version in meta header")
|
||||||
|
}
|
||||||
|
|
||||||
|
var ver versionsdk.Version
|
||||||
|
ver.ReadFromV2(*verV2)
|
||||||
|
|
||||||
|
ni, err := s.netInfo.Dump(ver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var niV2 netmap.NetworkInfo
|
||||||
|
ni.WriteToV2(&niV2)
|
||||||
|
|
||||||
body := new(netmap.NetworkInfoResponseBody)
|
body := new(netmap.NetworkInfoResponseBody)
|
||||||
body.SetNetworkInfo(ni)
|
body.SetNetworkInfo(&niV2)
|
||||||
|
|
||||||
resp := new(netmap.NetworkInfoResponse)
|
resp := new(netmap.NetworkInfoResponse)
|
||||||
resp.SetBody(body)
|
resp.SetBody(body)
|
||||||
|
|
|
@ -132,20 +132,26 @@ func (c senderClassifier) isContainerKey(
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupKeyInContainer(
|
func lookupKeyInContainer(
|
||||||
nm *netmap.Netmap,
|
nm *netmap.NetMap,
|
||||||
owner, idCnr []byte,
|
owner, idCnr []byte,
|
||||||
cnr *container.Container) (bool, error) {
|
cnr *container.Container) (bool, error) {
|
||||||
cnrNodes, err := nm.GetContainerNodes(cnr.PlacementPolicy(), idCnr)
|
policy := cnr.PlacementPolicy()
|
||||||
|
if policy == nil {
|
||||||
|
return false, errors.New("missing placement policy in container")
|
||||||
|
}
|
||||||
|
|
||||||
|
cnrVectors, err := nm.ContainerNodes(*policy, idCnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
flatCnrNodes := cnrNodes.Flatten() // we need single array to iterate on
|
for i := range cnrVectors {
|
||||||
for i := range flatCnrNodes {
|
for j := range cnrVectors[i] {
|
||||||
if bytes.Equal(flatCnrNodes[i].PublicKey(), owner) {
|
if bytes.Equal(cnrVectors[i][j].PublicKey(), owner) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/client"
|
"github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
|
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
||||||
|
@ -18,6 +19,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
|
netmaptest "github.com/nspcc-dev/neofs-sdk-go/netmap/test"
|
||||||
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
objectSDK "github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
|
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
|
||||||
|
@ -38,7 +40,7 @@ type testTraverserGenerator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type testPlacementBuilder struct {
|
type testPlacementBuilder struct {
|
||||||
vectors map[string][]netmap.Nodes
|
vectors map[string][][]netmap.NodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type testClientCache struct {
|
type testClientCache struct {
|
||||||
|
@ -81,7 +83,7 @@ func (g *testTraverserGenerator) GenerateTraverser(cnr cid.ID, obj *oid.ID, e ui
|
||||||
return placement.NewTraverser(opts...)
|
return placement.NewTraverser(opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *testPlacementBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, _ *netmap.PlacementPolicy) ([]netmap.Nodes, error) {
|
func (p *testPlacementBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, _ netmap.PlacementPolicy) ([][]netmap.NodeInfo, error) {
|
||||||
var addr oid.Address
|
var addr oid.Address
|
||||||
addr.SetContainer(cnr)
|
addr.SetContainer(cnr)
|
||||||
|
|
||||||
|
@ -392,8 +394,8 @@ func TestGetLocalOnly(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNodeMatrix(t testing.TB, dim []int) ([]netmap.Nodes, [][]string) {
|
func testNodeMatrix(t testing.TB, dim []int) ([][]netmap.NodeInfo, [][]string) {
|
||||||
mNodes := make([]netmap.Nodes, len(dim))
|
mNodes := make([][]netmap.NodeInfo, len(dim))
|
||||||
mAddr := make([][]string, len(dim))
|
mAddr := make([][]string, len(dim))
|
||||||
|
|
||||||
for i := range dim {
|
for i := range dim {
|
||||||
|
@ -406,20 +408,20 @@ func testNodeMatrix(t testing.TB, dim []int) ([]netmap.Nodes, [][]string) {
|
||||||
strconv.Itoa(60000+j),
|
strconv.Itoa(60000+j),
|
||||||
)
|
)
|
||||||
|
|
||||||
ni := netmap.NewNodeInfo()
|
var ni netmap.NodeInfo
|
||||||
ni.SetAddresses(a)
|
ni.SetNetworkEndpoints(a)
|
||||||
|
|
||||||
var na network.AddressGroup
|
var na network.AddressGroup
|
||||||
|
|
||||||
err := na.FromIterator(ni)
|
err := na.FromIterator(netmapcore.Node(ni))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
as[j] = network.StringifyGroup(na)
|
as[j] = network.StringifyGroup(na)
|
||||||
|
|
||||||
ns[j] = *ni
|
ns[j] = ni
|
||||||
}
|
}
|
||||||
|
|
||||||
mNodes[i] = netmap.NodesFromInfo(ns)
|
mNodes[i] = ns
|
||||||
mAddr[i] = as
|
mAddr[i] = as
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,7 +466,8 @@ func generateChain(ln int, cnr cid.ID) ([]*objectSDK.Object, []oid.ID, []byte) {
|
||||||
func TestGetRemoteSmall(t *testing.T) {
|
func TestGetRemoteSmall(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
cnr := container.New(container.WithPolicy(new(netmap.PlacementPolicy)))
|
pp := netmaptest.PlacementPolicy()
|
||||||
|
cnr := container.New(container.WithPolicy(&pp))
|
||||||
idCnr := container.CalculateID(cnr)
|
idCnr := container.CalculateID(cnr)
|
||||||
|
|
||||||
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
||||||
|
@ -527,7 +530,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
ns, as := testNodeMatrix(t, []int{2})
|
ns, as := testNodeMatrix(t, []int{2})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -590,7 +593,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
ns, as := testNodeMatrix(t, []int{2})
|
ns, as := testNodeMatrix(t, []int{2})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -634,7 +637,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
ns, as := testNodeMatrix(t, []int{2})
|
ns, as := testNodeMatrix(t, []int{2})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -708,7 +711,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
c2.addResult(splitAddr, nil, apistatus.ObjectNotFound{})
|
c2.addResult(splitAddr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
splitAddr.EncodeToString(): ns,
|
splitAddr.EncodeToString(): ns,
|
||||||
},
|
},
|
||||||
|
@ -781,7 +784,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
c2.addResult(child2Addr, nil, apistatus.ObjectNotFound{})
|
c2.addResult(child2Addr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
linkAddr.EncodeToString(): ns,
|
linkAddr.EncodeToString(): ns,
|
||||||
child1Addr.EncodeToString(): ns,
|
child1Addr.EncodeToString(): ns,
|
||||||
|
@ -858,7 +861,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
c2.addResult(child2Addr, children[1], nil)
|
c2.addResult(child2Addr, children[1], nil)
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
linkAddr.EncodeToString(): ns,
|
linkAddr.EncodeToString(): ns,
|
||||||
child1Addr.EncodeToString(): ns,
|
child1Addr.EncodeToString(): ns,
|
||||||
|
@ -924,7 +927,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
c2.addResult(splitAddr, nil, apistatus.ObjectNotFound{})
|
c2.addResult(splitAddr, nil, apistatus.ObjectNotFound{})
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
splitAddr.EncodeToString(): ns,
|
splitAddr.EncodeToString(): ns,
|
||||||
},
|
},
|
||||||
|
@ -988,7 +991,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
c2.addResult(rightAddr, rightObj, nil)
|
c2.addResult(rightAddr, rightObj, nil)
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
rightAddr.EncodeToString(): ns,
|
rightAddr.EncodeToString(): ns,
|
||||||
preRightAddr.EncodeToString(): ns,
|
preRightAddr.EncodeToString(): ns,
|
||||||
|
@ -1058,7 +1061,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{},
|
vectors: map[string][][]netmap.NodeInfo{},
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.vectors[addr.EncodeToString()] = ns
|
builder.vectors[addr.EncodeToString()] = ns
|
||||||
|
@ -1116,7 +1119,8 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
func TestGetFromPastEpoch(t *testing.T) {
|
func TestGetFromPastEpoch(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
cnr := container.New(container.WithPolicy(new(netmap.PlacementPolicy)))
|
pp := netmaptest.PlacementPolicy()
|
||||||
|
cnr := container.New(container.WithPolicy(&pp))
|
||||||
idCnr := container.CalculateID(cnr)
|
idCnr := container.CalculateID(cnr)
|
||||||
|
|
||||||
addr := oidtest.Address()
|
addr := oidtest.Address()
|
||||||
|
@ -1153,12 +1157,12 @@ func TestGetFromPastEpoch(t *testing.T) {
|
||||||
c: cnr,
|
c: cnr,
|
||||||
b: map[uint64]placement.Builder{
|
b: map[uint64]placement.Builder{
|
||||||
curEpoch: &testPlacementBuilder{
|
curEpoch: &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns[:1],
|
addr.EncodeToString(): ns[:1],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
curEpoch - 1: &testPlacementBuilder{
|
curEpoch - 1: &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns[1:],
|
addr.EncodeToString(): ns[1:],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
|
netmapCore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
internalclient "github.com/nspcc-dev/neofs-node/pkg/services/object/internal/client"
|
internalclient "github.com/nspcc-dev/neofs-node/pkg/services/object/internal/client"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
|
@ -29,7 +30,7 @@ type RemoteHeader struct {
|
||||||
type RemoteHeadPrm struct {
|
type RemoteHeadPrm struct {
|
||||||
commonHeadPrm *Prm
|
commonHeadPrm *Prm
|
||||||
|
|
||||||
node *netmap.NodeInfo
|
node netmap.NodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteOpTTL = 1
|
const remoteOpTTL = 1
|
||||||
|
@ -45,7 +46,7 @@ func NewRemoteHeader(keyStorage *util.KeyStorage, cache ClientConstructor) *Remo
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNodeInfo sets information about the remote node.
|
// WithNodeInfo sets information about the remote node.
|
||||||
func (p *RemoteHeadPrm) WithNodeInfo(v *netmap.NodeInfo) *RemoteHeadPrm {
|
func (p *RemoteHeadPrm) WithNodeInfo(v netmap.NodeInfo) *RemoteHeadPrm {
|
||||||
if p != nil {
|
if p != nil {
|
||||||
p.node = v
|
p.node = v
|
||||||
}
|
}
|
||||||
|
@ -71,7 +72,7 @@ func (h *RemoteHeader) Head(ctx context.Context, prm *RemoteHeadPrm) (*object.Ob
|
||||||
|
|
||||||
var info clientcore.NodeInfo
|
var info clientcore.NodeInfo
|
||||||
|
|
||||||
err = clientcore.NodeInfoFromRawNetmapElement(&info, prm.node)
|
err = clientcore.NodeInfoFromRawNetmapElement(&info, netmapCore.Node(prm.node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parse client node info: %w", err)
|
return nil, fmt.Errorf("parse client node info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
|
netmapCore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
internalclient "github.com/nspcc-dev/neofs-node/pkg/services/object/internal/client"
|
internalclient "github.com/nspcc-dev/neofs-node/pkg/services/object/internal/client"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transformer"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transformer"
|
||||||
|
@ -36,7 +37,7 @@ type RemoteSender struct {
|
||||||
|
|
||||||
// RemotePutPrm groups remote put operation parameters.
|
// RemotePutPrm groups remote put operation parameters.
|
||||||
type RemotePutPrm struct {
|
type RemotePutPrm struct {
|
||||||
node *netmap.NodeInfo
|
node netmap.NodeInfo
|
||||||
|
|
||||||
obj *object.Object
|
obj *object.Object
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,7 @@ func NewRemoteSender(keyStorage *util.KeyStorage, cons ClientConstructor) *Remot
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNodeInfo sets information about the remote node.
|
// WithNodeInfo sets information about the remote node.
|
||||||
func (p *RemotePutPrm) WithNodeInfo(v *netmap.NodeInfo) *RemotePutPrm {
|
func (p *RemotePutPrm) WithNodeInfo(v netmap.NodeInfo) *RemotePutPrm {
|
||||||
if p != nil {
|
if p != nil {
|
||||||
p.node = v
|
p.node = v
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,7 @@ func (s *RemoteSender) PutObject(ctx context.Context, p *RemotePutPrm) error {
|
||||||
clientConstructor: s.clientConstructor,
|
clientConstructor: s.clientConstructor,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := clientcore.NodeInfoFromRawNetmapElement(&t.nodeInfo, p.node)
|
err := clientcore.NodeInfoFromRawNetmapElement(&t.nodeInfo, netmapCore.Node(p.node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parse client node info: %w", err)
|
return fmt.Errorf("parse client node info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
||||||
|
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/util"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||||
|
@ -37,7 +38,7 @@ type testTraverserGenerator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type testPlacementBuilder struct {
|
type testPlacementBuilder struct {
|
||||||
vectors map[string][]netmap.Nodes
|
vectors map[string][][]netmap.NodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type testClientCache struct {
|
type testClientCache struct {
|
||||||
|
@ -73,7 +74,7 @@ func (g *testTraverserGenerator) generateTraverser(_ cid.ID, epoch uint64) (*pla
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *testPlacementBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, _ *netmap.PlacementPolicy) ([]netmap.Nodes, error) {
|
func (p *testPlacementBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, _ netmap.PlacementPolicy) ([][]netmap.NodeInfo, error) {
|
||||||
var addr oid.Address
|
var addr oid.Address
|
||||||
addr.SetContainer(cnr)
|
addr.SetContainer(cnr)
|
||||||
|
|
||||||
|
@ -86,7 +87,7 @@ func (p *testPlacementBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, _ *netmap
|
||||||
return nil, errors.New("vectors for address not found")
|
return nil, errors.New("vectors for address not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
res := make([]netmap.Nodes, len(vs))
|
res := make([][]netmap.NodeInfo, len(vs))
|
||||||
copy(res, vs)
|
copy(res, vs)
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
|
@ -193,8 +194,8 @@ func TestGetLocalOnly(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNodeMatrix(t testing.TB, dim []int) ([]netmap.Nodes, [][]string) {
|
func testNodeMatrix(t testing.TB, dim []int) ([][]netmap.NodeInfo, [][]string) {
|
||||||
mNodes := make([]netmap.Nodes, len(dim))
|
mNodes := make([][]netmap.NodeInfo, len(dim))
|
||||||
mAddr := make([][]string, len(dim))
|
mAddr := make([][]string, len(dim))
|
||||||
|
|
||||||
for i := range dim {
|
for i := range dim {
|
||||||
|
@ -207,20 +208,20 @@ func testNodeMatrix(t testing.TB, dim []int) ([]netmap.Nodes, [][]string) {
|
||||||
strconv.Itoa(60000+j),
|
strconv.Itoa(60000+j),
|
||||||
)
|
)
|
||||||
|
|
||||||
ni := netmap.NewNodeInfo()
|
var ni netmap.NodeInfo
|
||||||
ni.SetAddresses(a)
|
ni.SetNetworkEndpoints(a)
|
||||||
|
|
||||||
var na network.AddressGroup
|
var na network.AddressGroup
|
||||||
|
|
||||||
err := na.FromIterator(ni)
|
err := na.FromIterator(netmapcore.Node(ni))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
as[j] = network.StringifyGroup(na)
|
as[j] = network.StringifyGroup(na)
|
||||||
|
|
||||||
ns[j] = *ni
|
ns[j] = ni
|
||||||
}
|
}
|
||||||
|
|
||||||
mNodes[i] = netmap.NodesFromInfo(ns)
|
mNodes[i] = ns
|
||||||
mAddr[i] = as
|
mAddr[i] = as
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,15 +233,15 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
|
|
||||||
placementDim := []int{2}
|
placementDim := []int{2}
|
||||||
|
|
||||||
rs := make([]netmap.Replica, len(placementDim))
|
rs := make([]netmap.ReplicaDescriptor, len(placementDim))
|
||||||
for i := range placementDim {
|
for i := range placementDim {
|
||||||
rs[i].SetCount(uint32(placementDim[i]))
|
rs[i].SetNumberOfObjects(uint32(placementDim[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pp := netmap.NewPlacementPolicy()
|
var pp netmap.PlacementPolicy
|
||||||
pp.SetReplicas(rs...)
|
pp.AddReplicas(rs...)
|
||||||
|
|
||||||
cnr := container.New(container.WithPolicy(pp))
|
cnr := container.New(container.WithPolicy(&pp))
|
||||||
id := container.CalculateID(cnr)
|
id := container.CalculateID(cnr)
|
||||||
|
|
||||||
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
||||||
|
@ -278,7 +279,7 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
ns, as := testNodeMatrix(t, placementDim)
|
ns, as := testNodeMatrix(t, placementDim)
|
||||||
|
|
||||||
builder := &testPlacementBuilder{
|
builder := &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns,
|
addr.EncodeToString(): ns,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -317,16 +318,16 @@ func TestGetFromPastEpoch(t *testing.T) {
|
||||||
|
|
||||||
placementDim := []int{2, 2}
|
placementDim := []int{2, 2}
|
||||||
|
|
||||||
rs := make([]netmap.Replica, len(placementDim))
|
rs := make([]netmap.ReplicaDescriptor, len(placementDim))
|
||||||
|
|
||||||
for i := range placementDim {
|
for i := range placementDim {
|
||||||
rs[i].SetCount(uint32(placementDim[i]))
|
rs[i].SetNumberOfObjects(uint32(placementDim[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pp := netmap.NewPlacementPolicy()
|
var pp netmap.PlacementPolicy
|
||||||
pp.SetReplicas(rs...)
|
pp.AddReplicas(rs...)
|
||||||
|
|
||||||
cnr := container.New(container.WithPolicy(pp))
|
cnr := container.New(container.WithPolicy(&pp))
|
||||||
idCnr := container.CalculateID(cnr)
|
idCnr := container.CalculateID(cnr)
|
||||||
|
|
||||||
var addr oid.Address
|
var addr oid.Address
|
||||||
|
@ -360,12 +361,12 @@ func TestGetFromPastEpoch(t *testing.T) {
|
||||||
c: cnr,
|
c: cnr,
|
||||||
b: map[uint64]placement.Builder{
|
b: map[uint64]placement.Builder{
|
||||||
curEpoch: &testPlacementBuilder{
|
curEpoch: &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns[:1],
|
addr.EncodeToString(): ns[:1],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
curEpoch - 1: &testPlacementBuilder{
|
curEpoch - 1: &testPlacementBuilder{
|
||||||
vectors: map[string][]netmap.Nodes{
|
vectors: map[string][][]netmap.NodeInfo{
|
||||||
addr.EncodeToString(): ns[1:],
|
addr.EncodeToString(): ns[1:],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,7 +43,7 @@ func NewLocalPlacement(b placement.Builder, s netmap.AnnouncedKeys) placement.Bu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *localPlacement) BuildPlacement(cnr cid.ID, obj *oid.ID, policy *netmapSDK.PlacementPolicy) ([]netmapSDK.Nodes, error) {
|
func (p *localPlacement) BuildPlacement(cnr cid.ID, obj *oid.ID, policy netmapSDK.PlacementPolicy) ([][]netmapSDK.NodeInfo, error) {
|
||||||
vs, err := p.builder.BuildPlacement(cnr, obj, policy)
|
vs, err := p.builder.BuildPlacement(cnr, obj, policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("(%T) could not build object placement: %w", p, err)
|
return nil, fmt.Errorf("(%T) could not build object placement: %w", p, err)
|
||||||
|
@ -53,13 +53,13 @@ func (p *localPlacement) BuildPlacement(cnr cid.ID, obj *oid.ID, policy *netmapS
|
||||||
for j := range vs[i] {
|
for j := range vs[i] {
|
||||||
var addr network.AddressGroup
|
var addr network.AddressGroup
|
||||||
|
|
||||||
err := addr.FromIterator(vs[i][j])
|
err := addr.FromIterator(network.NodeEndpointsIterator(vs[i][j]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.netmapKeys.IsLocalKey(vs[i][j].PublicKey()) {
|
if p.netmapKeys.IsLocalKey(vs[i][j].PublicKey()) {
|
||||||
return []netmapSDK.Nodes{{vs[i][j]}}, nil
|
return [][]netmapSDK.NodeInfo{{vs[i][j]}}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ func NewRemotePlacementBuilder(b placement.Builder, s netmap.AnnouncedKeys) plac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *remotePlacement) BuildPlacement(cnr cid.ID, obj *oid.ID, policy *netmapSDK.PlacementPolicy) ([]netmapSDK.Nodes, error) {
|
func (p *remotePlacement) BuildPlacement(cnr cid.ID, obj *oid.ID, policy netmapSDK.PlacementPolicy) ([][]netmapSDK.NodeInfo, error) {
|
||||||
vs, err := p.builder.BuildPlacement(cnr, obj, policy)
|
vs, err := p.builder.BuildPlacement(cnr, obj, policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("(%T) could not build object placement: %w", p, err)
|
return nil, fmt.Errorf("(%T) could not build object placement: %w", p, err)
|
||||||
|
@ -86,7 +86,7 @@ func (p *remotePlacement) BuildPlacement(cnr cid.ID, obj *oid.ID, policy *netmap
|
||||||
for j := 0; j < len(vs[i]); j++ {
|
for j := 0; j < len(vs[i]); j++ {
|
||||||
var addr network.AddressGroup
|
var addr network.AddressGroup
|
||||||
|
|
||||||
err := addr.FromIterator(vs[i][j])
|
err := addr.FromIterator(network.NodeEndpointsIterator(vs[i][j]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ type netMapBuilder struct {
|
||||||
nmSrc netmap.Source
|
nmSrc netmap.Source
|
||||||
// mtx protects lastNm and containerCache fields.
|
// mtx protects lastNm and containerCache fields.
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
lastNm *netmapSDK.Netmap
|
lastNm *netmapSDK.NetMap
|
||||||
// containerCache caches container nodes by ID. It is used to skip `GetContainerNodes` invocation if
|
// containerCache caches container nodes by ID. It is used to skip `GetContainerNodes` invocation if
|
||||||
// neither netmap nor container has changed.
|
// neither netmap nor container has changed.
|
||||||
containerCache simplelru.LRUCache
|
containerCache simplelru.LRUCache
|
||||||
|
@ -25,13 +25,13 @@ type netMapBuilder struct {
|
||||||
type netMapSrc struct {
|
type netMapSrc struct {
|
||||||
netmap.Source
|
netmap.Source
|
||||||
|
|
||||||
nm *netmapSDK.Netmap
|
nm *netmapSDK.NetMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultContainerCacheSize is the default size for the container cache.
|
// defaultContainerCacheSize is the default size for the container cache.
|
||||||
const defaultContainerCacheSize = 10
|
const defaultContainerCacheSize = 10
|
||||||
|
|
||||||
func NewNetworkMapBuilder(nm *netmapSDK.Netmap) Builder {
|
func NewNetworkMapBuilder(nm *netmapSDK.NetMap) Builder {
|
||||||
cache, _ := simplelru.NewLRU(defaultContainerCacheSize, nil) // no error
|
cache, _ := simplelru.NewLRU(defaultContainerCacheSize, nil) // no error
|
||||||
return &netMapBuilder{
|
return &netMapBuilder{
|
||||||
nmSrc: &netMapSrc{nm: nm},
|
nmSrc: &netMapSrc{nm: nm},
|
||||||
|
@ -47,11 +47,11 @@ func NewNetworkMapSourceBuilder(nmSrc netmap.Source) Builder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *netMapSrc) GetNetMap(diff uint64) (*netmapSDK.Netmap, error) {
|
func (s *netMapSrc) GetNetMap(diff uint64) (*netmapSDK.NetMap, error) {
|
||||||
return s.nm, nil
|
return s.nm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *netMapBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, p *netmapSDK.PlacementPolicy) ([]netmapSDK.Nodes, error) {
|
func (b *netMapBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, p netmapSDK.PlacementPolicy) ([][]netmapSDK.NodeInfo, error) {
|
||||||
nm, err := netmap.GetLatestNetworkMap(b.nmSrc)
|
nm, err := netmap.GetLatestNetworkMap(b.nmSrc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get network map: %w", err)
|
return nil, fmt.Errorf("could not get network map: %w", err)
|
||||||
|
@ -65,7 +65,7 @@ func (b *netMapBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, p *netmapSDK.Pla
|
||||||
raw, ok := b.containerCache.Get(string(binCnr))
|
raw, ok := b.containerCache.Get(string(binCnr))
|
||||||
b.mtx.Unlock()
|
b.mtx.Unlock()
|
||||||
if ok {
|
if ok {
|
||||||
cn := raw.(netmapSDK.ContainerNodes)
|
cn := raw.([][]netmapSDK.NodeInfo)
|
||||||
return BuildObjectPlacement(nm, cn, obj)
|
return BuildObjectPlacement(nm, cn, obj)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -73,7 +73,7 @@ func (b *netMapBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, p *netmapSDK.Pla
|
||||||
b.mtx.Unlock()
|
b.mtx.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
cn, err := nm.GetContainerNodes(p, binCnr)
|
cn, err := nm.ContainerNodes(p, binCnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get container nodes: %w", err)
|
return nil, fmt.Errorf("could not get container nodes: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -85,15 +85,15 @@ func (b *netMapBuilder) BuildPlacement(cnr cid.ID, obj *oid.ID, p *netmapSDK.Pla
|
||||||
return BuildObjectPlacement(nm, cn, obj)
|
return BuildObjectPlacement(nm, cn, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildObjectPlacement(nm *netmapSDK.Netmap, cnrNodes netmapSDK.ContainerNodes, id *oid.ID) ([]netmapSDK.Nodes, error) {
|
func BuildObjectPlacement(nm *netmapSDK.NetMap, cnrNodes [][]netmapSDK.NodeInfo, id *oid.ID) ([][]netmapSDK.NodeInfo, error) {
|
||||||
if id == nil {
|
if id == nil {
|
||||||
return cnrNodes.Replicas(), nil
|
return cnrNodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
binObj := make([]byte, sha256.Size)
|
binObj := make([]byte, sha256.Size)
|
||||||
id.Encode(binObj)
|
id.Encode(binObj)
|
||||||
|
|
||||||
on, err := nm.GetPlacementVectors(cnrNodes, binObj)
|
on, err := nm.PlacementVectors(cnrNodes, binObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get placement vectors for object: %w", err)
|
return nil, fmt.Errorf("could not get placement vectors for object: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -102,8 +102,15 @@ func BuildObjectPlacement(nm *netmapSDK.Netmap, cnrNodes netmapSDK.ContainerNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlattenNodes appends each row to the flat list.
|
// FlattenNodes appends each row to the flat list.
|
||||||
func FlattenNodes(ns []netmapSDK.Nodes) netmapSDK.Nodes {
|
func FlattenNodes(ns [][]netmapSDK.NodeInfo) []netmapSDK.NodeInfo {
|
||||||
result := make(netmapSDK.Nodes, 0, len(ns))
|
var sz int
|
||||||
|
|
||||||
|
for i := range ns {
|
||||||
|
sz += len(ns[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]netmapSDK.NodeInfo, 0, sz)
|
||||||
|
|
||||||
for i := range ns {
|
for i := range ns {
|
||||||
result = append(result, ns[i]...)
|
result = append(result, ns[i]...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ type Builder interface {
|
||||||
//
|
//
|
||||||
// Must return all container nodes if object identifier
|
// Must return all container nodes if object identifier
|
||||||
// is nil.
|
// is nil.
|
||||||
BuildPlacement(cid.ID, *oid.ID, *netmap.PlacementPolicy) ([]netmap.Nodes, error)
|
BuildPlacement(cid.ID, *oid.ID, netmap.PlacementPolicy) ([][]netmap.NodeInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option represents placement traverser option.
|
// Option represents placement traverser option.
|
||||||
|
@ -31,7 +31,7 @@ type Option func(*cfg)
|
||||||
type Traverser struct {
|
type Traverser struct {
|
||||||
mtx *sync.RWMutex
|
mtx *sync.RWMutex
|
||||||
|
|
||||||
vectors []netmap.Nodes
|
vectors [][]netmap.NodeInfo
|
||||||
|
|
||||||
rem []int
|
rem []int
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ func NewTraverser(opts ...Option) (*Traverser, error) {
|
||||||
return nil, fmt.Errorf("%s: %w", invalidOptsMsg, errNilPolicy)
|
return nil, fmt.Errorf("%s: %w", invalidOptsMsg, errNilPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
ns, err := cfg.builder.BuildPlacement(cfg.cnr, cfg.obj, cfg.policy)
|
ns, err := cfg.builder.BuildPlacement(cfg.cnr, cfg.obj, *cfg.policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not build placement: %w", err)
|
return nil, fmt.Errorf("could not build placement: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -88,12 +88,12 @@ func NewTraverser(opts ...Option) (*Traverser, error) {
|
||||||
ns = flatNodes(ns)
|
ns = flatNodes(ns)
|
||||||
rem = []int{int(*cfg.flatSuccess)}
|
rem = []int{int(*cfg.flatSuccess)}
|
||||||
} else {
|
} else {
|
||||||
rs := cfg.policy.Replicas()
|
replNum := cfg.policy.NumberOfReplicas()
|
||||||
rem = make([]int, 0, len(rs))
|
rem = make([]int, 0, replNum)
|
||||||
|
|
||||||
for i := range rs {
|
for i := 0; i < replNum; i++ {
|
||||||
if cfg.trackCopies {
|
if cfg.trackCopies {
|
||||||
rem = append(rem, int(rs[i].Count()))
|
rem = append(rem, int(cfg.policy.ReplicaNumberByIndex(i)))
|
||||||
} else {
|
} else {
|
||||||
rem = append(rem, -1)
|
rem = append(rem, -1)
|
||||||
}
|
}
|
||||||
|
@ -107,18 +107,18 @@ func NewTraverser(opts ...Option) (*Traverser, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func flatNodes(ns []netmap.Nodes) []netmap.Nodes {
|
func flatNodes(ns [][]netmap.NodeInfo) [][]netmap.NodeInfo {
|
||||||
sz := 0
|
sz := 0
|
||||||
for i := range ns {
|
for i := range ns {
|
||||||
sz += len(ns[i])
|
sz += len(ns[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
flat := make(netmap.Nodes, 0, sz)
|
flat := make([]netmap.NodeInfo, 0, sz)
|
||||||
for i := range ns {
|
for i := range ns {
|
||||||
flat = append(flat, ns[i]...)
|
flat = append(flat, ns[i]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return []netmap.Nodes{flat}
|
return [][]netmap.NodeInfo{flat}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node is a descriptor of storage node with information required for intra-container communication.
|
// Node is a descriptor of storage node with information required for intra-container communication.
|
||||||
|
@ -161,7 +161,7 @@ func (t *Traverser) Next() []Node {
|
||||||
nodes := make([]Node, count)
|
nodes := make([]Node, count)
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
err := nodes[i].addresses.FromIterator(t.vectors[0][i])
|
err := nodes[i].addresses.FromIterator(network.NodeEndpointsIterator(t.vectors[0][i]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
@ -13,24 +14,24 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type testBuilder struct {
|
type testBuilder struct {
|
||||||
vectors []netmap.Nodes
|
vectors [][]netmap.NodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b testBuilder) BuildPlacement(cid.ID, *oid.ID, *netmap.PlacementPolicy) ([]netmap.Nodes, error) {
|
func (b testBuilder) BuildPlacement(cid.ID, *oid.ID, netmap.PlacementPolicy) ([][]netmap.NodeInfo, error) {
|
||||||
return b.vectors, nil
|
return b.vectors, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNode(v uint32) (n netmap.NodeInfo) {
|
func testNode(v uint32) (n netmap.NodeInfo) {
|
||||||
n.SetAddresses("/ip4/0.0.0.0/tcp/" + strconv.Itoa(int(v)))
|
n.SetNetworkEndpoints("/ip4/0.0.0.0/tcp/" + strconv.Itoa(int(v)))
|
||||||
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyVectors(v []netmap.Nodes) []netmap.Nodes {
|
func copyVectors(v [][]netmap.NodeInfo) [][]netmap.NodeInfo {
|
||||||
vc := make([]netmap.Nodes, 0, len(v))
|
vc := make([][]netmap.NodeInfo, 0, len(v))
|
||||||
|
|
||||||
for i := range v {
|
for i := range v {
|
||||||
ns := make(netmap.Nodes, len(v[i]))
|
ns := make([]netmap.NodeInfo, len(v[i]))
|
||||||
copy(ns, v[i])
|
copy(ns, v[i])
|
||||||
|
|
||||||
vc = append(vc, ns)
|
vc = append(vc, ns)
|
||||||
|
@ -39,9 +40,9 @@ func copyVectors(v []netmap.Nodes) []netmap.Nodes {
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPlacement(t *testing.T, ss, rs []int) ([]netmap.Nodes, *container.Container) {
|
func testPlacement(t *testing.T, ss, rs []int) ([][]netmap.NodeInfo, *container.Container) {
|
||||||
nodes := make([]netmap.Nodes, 0, len(rs))
|
nodes := make([][]netmap.NodeInfo, 0, len(rs))
|
||||||
replicas := make([]netmap.Replica, 0, len(rs))
|
replicas := make([]netmap.ReplicaDescriptor, 0, len(rs))
|
||||||
num := uint32(0)
|
num := uint32(0)
|
||||||
|
|
||||||
for i := range ss {
|
for i := range ss {
|
||||||
|
@ -52,24 +53,24 @@ func testPlacement(t *testing.T, ss, rs []int) ([]netmap.Nodes, *container.Conta
|
||||||
num++
|
num++
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = append(nodes, netmap.NodesFromInfo(ns))
|
nodes = append(nodes, ns)
|
||||||
|
|
||||||
var s netmap.Replica
|
var rd netmap.ReplicaDescriptor
|
||||||
s.SetCount(uint32(rs[i]))
|
rd.SetNumberOfObjects(uint32(rs[i]))
|
||||||
|
|
||||||
replicas = append(replicas, s)
|
replicas = append(replicas, rd)
|
||||||
}
|
}
|
||||||
|
|
||||||
policy := new(netmap.PlacementPolicy)
|
policy := new(netmap.PlacementPolicy)
|
||||||
policy.SetReplicas(replicas...)
|
policy.AddReplicas(replicas...)
|
||||||
|
|
||||||
return nodes, container.New(container.WithPolicy(policy))
|
return nodes, container.New(container.WithPolicy(policy))
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertSameAddress(t *testing.T, ni *netmap.NodeInfo, addr network.AddressGroup) {
|
func assertSameAddress(t *testing.T, ni netmap.NodeInfo, addr network.AddressGroup) {
|
||||||
var netAddr network.AddressGroup
|
var netAddr network.AddressGroup
|
||||||
|
|
||||||
err := netAddr.FromIterator(ni)
|
err := netAddr.FromIterator(netmapcore.Node(ni))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, netAddr.Intersects(addr))
|
require.True(t, netAddr.Intersects(addr))
|
||||||
}
|
}
|
||||||
|
@ -96,7 +97,7 @@ func TestTraverserObjectScenarios(t *testing.T) {
|
||||||
require.Len(t, addrs, len(nodes[i]))
|
require.Len(t, addrs, len(nodes[i]))
|
||||||
|
|
||||||
for j, n := range nodes[i] {
|
for j, n := range nodes[i] {
|
||||||
assertSameAddress(t, n.NodeInfo, addrs[j].Addresses())
|
assertSameAddress(t, n, addrs[j].Addresses())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +128,7 @@ func TestTraverserObjectScenarios(t *testing.T) {
|
||||||
|
|
||||||
var n network.AddressGroup
|
var n network.AddressGroup
|
||||||
|
|
||||||
err = n.FromIterator(nodes[1][0])
|
err = n.FromIterator(netmapcore.Node(nodes[1][0]))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, []Node{{addresses: n}}, tr.Next())
|
require.Equal(t, []Node{{addresses: n}}, tr.Next())
|
||||||
|
@ -153,7 +154,7 @@ func TestTraverserObjectScenarios(t *testing.T) {
|
||||||
require.Len(t, addrs, replicas[curVector])
|
require.Len(t, addrs, replicas[curVector])
|
||||||
|
|
||||||
for j := range addrs {
|
for j := range addrs {
|
||||||
assertSameAddress(t, nodes[curVector][i+j].NodeInfo, addrs[j].Addresses())
|
assertSameAddress(t, nodes[curVector][i+j], addrs[j].Addresses())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +186,7 @@ func TestTraverserObjectScenarios(t *testing.T) {
|
||||||
tr, err := NewTraverser(
|
tr, err := NewTraverser(
|
||||||
ForContainer(cnr),
|
ForContainer(cnr),
|
||||||
UseBuilder(&testBuilder{
|
UseBuilder(&testBuilder{
|
||||||
vectors: []netmap.Nodes{{nodes[1][1]}}, // single node (local)
|
vectors: [][]netmap.NodeInfo{{nodes[1][1]}}, // single node (local)
|
||||||
}),
|
}),
|
||||||
SuccessAfter(1),
|
SuccessAfter(1),
|
||||||
)
|
)
|
||||||
|
|
|
@ -45,9 +45,17 @@ func (p *Policer) processObject(ctx context.Context, addr oid.Address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
policy := cnr.PlacementPolicy()
|
policy := cnr.PlacementPolicy()
|
||||||
|
if policy == nil {
|
||||||
|
p.log.Error("missing placement policy in container",
|
||||||
|
zap.Stringer("cid", idCnr),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
obj := addr.Object()
|
obj := addr.Object()
|
||||||
|
|
||||||
nn, err := p.placementBuilder.BuildPlacement(idCnr, &obj, policy)
|
nn, err := p.placementBuilder.BuildPlacement(idCnr, &obj, *policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.log.Error("could not build placement vector for object",
|
p.log.Error("could not build placement vector for object",
|
||||||
zap.String("error", err.Error()),
|
zap.String("error", err.Error()),
|
||||||
|
@ -56,7 +64,6 @@ func (p *Policer) processObject(ctx context.Context, addr oid.Address) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
replicas := policy.Replicas()
|
|
||||||
c := &processPlacementContext{
|
c := &processPlacementContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
|
@ -76,7 +83,7 @@ func (p *Policer) processObject(ctx context.Context, addr oid.Address) {
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
p.processNodes(c, addr, nn[i], replicas[i].Count(), checkedNodes)
|
p.processNodes(c, addr, nn[i], policy.ReplicaNumberByIndex(i), checkedNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.needLocalCopy {
|
if !c.needLocalCopy {
|
||||||
|
@ -95,7 +102,7 @@ type processPlacementContext struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
|
func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
|
||||||
nodes netmap.Nodes, shortage uint32, checkedNodes nodeCache) {
|
nodes []netmap.NodeInfo, shortage uint32, checkedNodes nodeCache) {
|
||||||
prm := new(headsvc.RemoteHeadPrm).WithObjectAddress(addr)
|
prm := new(headsvc.RemoteHeadPrm).WithObjectAddress(addr)
|
||||||
|
|
||||||
for i := 0; shortage > 0 && i < len(nodes); i++ {
|
for i := 0; shortage > 0 && i < len(nodes); i++ {
|
||||||
|
@ -110,7 +117,8 @@ func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
|
||||||
|
|
||||||
shortage--
|
shortage--
|
||||||
} else {
|
} else {
|
||||||
if hasReplica, checked := checkedNodes[nodes[i].ID]; checked {
|
nodeID := nodes[i].Hash()
|
||||||
|
if hasReplica, checked := checkedNodes[nodeID]; checked {
|
||||||
if hasReplica {
|
if hasReplica {
|
||||||
// node already contains replica, no need to replicate
|
// node already contains replica, no need to replicate
|
||||||
nodes = append(nodes[:i], nodes[i+1:]...)
|
nodes = append(nodes[:i], nodes[i+1:]...)
|
||||||
|
@ -123,7 +131,7 @@ func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
|
||||||
|
|
||||||
callCtx, cancel := context.WithTimeout(ctx, p.headTimeout)
|
callCtx, cancel := context.WithTimeout(ctx, p.headTimeout)
|
||||||
|
|
||||||
_, err := p.remoteHeader.Head(callCtx, prm.WithNodeInfo(nodes[i].NodeInfo))
|
_, err := p.remoteHeader.Head(callCtx, prm.WithNodeInfo(nodes[i]))
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
|
@ -133,7 +141,7 @@ func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.IsErrObjectNotFound(err) {
|
if client.IsErrObjectNotFound(err) {
|
||||||
checkedNodes[nodes[i].ID] = false
|
checkedNodes[nodeID] = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +152,7 @@ func (p *Policer) processNodes(ctx *processPlacementContext, addr oid.Address,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
shortage--
|
shortage--
|
||||||
checkedNodes[nodes[i].ID] = true
|
checkedNodes[nodeID] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (p *Replicator) HandleTask(ctx context.Context, task *Task, res TaskResult)
|
||||||
|
|
||||||
callCtx, cancel := context.WithTimeout(ctx, p.putTimeout)
|
callCtx, cancel := context.WithTimeout(ctx, p.putTimeout)
|
||||||
|
|
||||||
err = p.remoteSender.PutObject(callCtx, prm.WithNodeInfo(task.nodes[i].NodeInfo))
|
err = p.remoteSender.PutObject(callCtx, prm.WithNodeInfo(task.nodes[i]))
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ func (p *Replicator) HandleTask(ctx context.Context, task *Task, res TaskResult)
|
||||||
|
|
||||||
task.quantity--
|
task.quantity--
|
||||||
|
|
||||||
res.SubmitSuccessfulReplication(task.nodes[i].ID)
|
res.SubmitSuccessfulReplication(task.nodes[i].Hash())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ type Task struct {
|
||||||
|
|
||||||
addr oid.Address
|
addr oid.Address
|
||||||
|
|
||||||
nodes netmap.Nodes
|
nodes []netmap.NodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithCopiesNumber sets number of copies to replicate.
|
// WithCopiesNumber sets number of copies to replicate.
|
||||||
|
@ -33,7 +33,7 @@ func (t *Task) WithObjectAddress(v oid.Address) *Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNodes sets a list of potential object holders.
|
// WithNodes sets a list of potential object holders.
|
||||||
func (t *Task) WithNodes(v netmap.Nodes) *Task {
|
func (t *Task) WithNodes(v []netmap.NodeInfo) *Task {
|
||||||
if t != nil {
|
if t != nil {
|
||||||
t.nodes = v
|
t.nodes = v
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,21 @@ func NewManagerBuilder(prm ManagersPrm, opts ...MngOption) ManagerBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// implements Server on apiNetmap.NodeInfo
|
||||||
|
type nodeServer apiNetmap.NodeInfo
|
||||||
|
|
||||||
|
func (x nodeServer) PublicKey() []byte {
|
||||||
|
return (apiNetmap.NodeInfo)(x).PublicKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x nodeServer) IterateAddresses(f func(string) bool) {
|
||||||
|
(apiNetmap.NodeInfo)(x).IterateNetworkEndpoints(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x nodeServer) NumberOfAddresses() int {
|
||||||
|
return (apiNetmap.NodeInfo)(x).NumberOfNetworkEndpoints()
|
||||||
|
}
|
||||||
|
|
||||||
// BuildManagers sorts nodes in NetMap with HRW algorithms and
|
// BuildManagers sorts nodes in NetMap with HRW algorithms and
|
||||||
// takes the next node after the current one as the only manager.
|
// takes the next node after the current one as the only manager.
|
||||||
func (mb *managerBuilder) BuildManagers(epoch uint64, p reputation.PeerID) ([]ServerInfo, error) {
|
func (mb *managerBuilder) BuildManagers(epoch uint64, p reputation.PeerID) ([]ServerInfo, error) {
|
||||||
|
@ -69,10 +84,12 @@ func (mb *managerBuilder) BuildManagers(epoch uint64, p reputation.PeerID) ([]Se
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a copy to keep order consistency of the origin netmap after sorting
|
nmNodes := nm.Nodes()
|
||||||
nodes := make([]apiNetmap.Node, len(nm.Nodes))
|
|
||||||
|
|
||||||
copy(nodes, nm.Nodes)
|
// make a copy to keep order consistency of the origin netmap after sorting
|
||||||
|
nodes := make([]apiNetmap.NodeInfo, len(nmNodes))
|
||||||
|
|
||||||
|
copy(nodes, nmNodes)
|
||||||
|
|
||||||
hrw.SortSliceByValue(nodes, epoch)
|
hrw.SortSliceByValue(nodes, epoch)
|
||||||
|
|
||||||
|
@ -84,7 +101,7 @@ func (mb *managerBuilder) BuildManagers(epoch uint64, p reputation.PeerID) ([]Se
|
||||||
managerIndex = 0
|
managerIndex = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return []ServerInfo{nodes[managerIndex]}, nil
|
return []ServerInfo{nodeServer(nodes[managerIndex])}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,104 +8,63 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const keyValueSeparator = ":"
|
||||||
pairSeparator = "/"
|
|
||||||
keyValueSeparator = ":"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
// ReadNodeAttributes parses node attributes from list of string in "Key:Value" format
|
||||||
errEmptyChain = errors.New("empty attribute chain")
|
// and writes them into netmap.NodeInfo instance. Supports escaped symbols
|
||||||
errNonUniqueBucket = errors.New("attributes must contain unique keys")
|
// "\:", "\/" and "\\".
|
||||||
errUnexpectedKey = errors.New("attributes contain unexpected key")
|
func ReadNodeAttributes(dst *netmap.NodeInfo, attrs []string) error {
|
||||||
)
|
cache := make(map[string]struct{}, len(attrs))
|
||||||
|
|
||||||
// ParseV2Attributes parses strings like "K1:V1/K2:V2/K3:V3" into netmap
|
|
||||||
// attributes. Supports escaped symbols "\:", "\/" and "\\".
|
|
||||||
func ParseV2Attributes(attrs []string, excl []string) ([]netmap.NodeAttribute, error) {
|
|
||||||
restricted := make(map[string]struct{}, len(excl))
|
|
||||||
for i := range excl {
|
|
||||||
restricted[excl[i]] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache := make(map[string]*netmap.NodeAttribute, len(attrs))
|
|
||||||
result := make([]netmap.NodeAttribute, 0, len(attrs))
|
|
||||||
|
|
||||||
for i := range attrs {
|
for i := range attrs {
|
||||||
line := strings.Trim(attrs[i], pairSeparator)
|
line := replaceEscaping(attrs[i], false) // replaced escaped symbols with non-printable symbols
|
||||||
line = replaceEscaping(line, false) // replaced escaped symbols with non-printable symbols
|
|
||||||
chain := strings.Split(line, pairSeparator)
|
words := strings.Split(line, keyValueSeparator)
|
||||||
if len(chain) == 0 {
|
if len(words) != 2 {
|
||||||
return nil, errEmptyChain
|
return errors.New("missing attribute key and/or value")
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentKey string // backtrack parents in next pairs
|
_, ok := cache[words[0]]
|
||||||
|
if ok {
|
||||||
for j := range chain {
|
return fmt.Errorf("duplicated keys %s", words[0])
|
||||||
pair := strings.Split(chain[j], keyValueSeparator)
|
|
||||||
if len(pair) != 2 {
|
|
||||||
return nil, fmt.Errorf("incorrect attribute pair %s", chain[j])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
key := pair[0]
|
cache[words[0]] = struct{}{}
|
||||||
value := pair[1]
|
|
||||||
|
|
||||||
attribute, present := cache[key]
|
|
||||||
if present && attribute.Value() != value {
|
|
||||||
return nil, errNonUniqueBucket
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := restricted[key]; ok {
|
|
||||||
return nil, errUnexpectedKey
|
|
||||||
}
|
|
||||||
|
|
||||||
if !present {
|
|
||||||
result = append(result, netmap.NodeAttribute{})
|
|
||||||
attribute = &result[len(result)-1]
|
|
||||||
cache[key] = attribute
|
|
||||||
|
|
||||||
// replace non-printable symbols with escaped symbols without escape character
|
// replace non-printable symbols with escaped symbols without escape character
|
||||||
key = replaceEscaping(key, true)
|
words[0] = replaceEscaping(words[0], true)
|
||||||
value = replaceEscaping(value, true)
|
words[1] = replaceEscaping(words[1], true)
|
||||||
|
fmt.Println(words[0], words[1])
|
||||||
|
|
||||||
attribute.SetKey(key)
|
if words[0] == "" {
|
||||||
attribute.SetValue(value)
|
return errors.New("empty key")
|
||||||
|
} else if words[1] == "" {
|
||||||
|
return errors.New("empty value")
|
||||||
}
|
}
|
||||||
|
|
||||||
if parentKey != "" {
|
dst.SetAttribute(words[0], words[1])
|
||||||
parentKeys := attribute.ParentKeys()
|
|
||||||
if !hasString(parentKeys, parentKey) {
|
|
||||||
attribute.SetParentKeys(append(parentKeys, parentKey)...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parentKey = key
|
return nil
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func replaceEscaping(target string, rollback bool) (s string) {
|
func replaceEscaping(target string, rollback bool) (s string) {
|
||||||
const escChar = `\`
|
const escChar = `\`
|
||||||
|
|
||||||
var (
|
var (
|
||||||
oldPairSep = escChar + pairSeparator
|
|
||||||
oldKVSep = escChar + keyValueSeparator
|
oldKVSep = escChar + keyValueSeparator
|
||||||
oldEsc = escChar + escChar
|
oldEsc = escChar + escChar
|
||||||
newPairSep = string(uint8(1))
|
|
||||||
newKVSep = string(uint8(2))
|
newKVSep = string(uint8(2))
|
||||||
newEsc = string(uint8(3))
|
newEsc = string(uint8(3))
|
||||||
)
|
)
|
||||||
|
|
||||||
if rollback {
|
if rollback {
|
||||||
oldPairSep, oldKVSep, oldEsc = newPairSep, newKVSep, newEsc
|
oldKVSep, oldEsc = newKVSep, newEsc
|
||||||
newPairSep = pairSeparator
|
|
||||||
newKVSep = keyValueSeparator
|
newKVSep = keyValueSeparator
|
||||||
newEsc = escChar
|
newEsc = escChar
|
||||||
}
|
}
|
||||||
|
|
||||||
s = strings.ReplaceAll(target, oldEsc, newEsc)
|
s = strings.ReplaceAll(target, oldEsc, newEsc)
|
||||||
s = strings.ReplaceAll(s, oldPairSep, newPairSep)
|
|
||||||
s = strings.ReplaceAll(s, oldKVSep, newKVSep)
|
s = strings.ReplaceAll(s, oldKVSep, newKVSep)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,117 +4,96 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/attributes"
|
"github.com/nspcc-dev/neofs-node/pkg/util/attributes"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseV2Attributes(t *testing.T) {
|
func testAttributeMap(t *testing.T, mSrc, mExp map[string]string) {
|
||||||
t.Run("empty", func(t *testing.T) {
|
var node netmap.NodeInfo
|
||||||
attrs, err := attributes.ParseV2Attributes(nil, nil)
|
|
||||||
|
s := make([]string, 0, len(mSrc))
|
||||||
|
for k, v := range mSrc {
|
||||||
|
s = append(s, k+":"+v)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := attributes.ReadNodeAttributes(&node, s)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, attrs, 0)
|
|
||||||
|
if mExp == nil {
|
||||||
|
mExp = mSrc
|
||||||
|
}
|
||||||
|
|
||||||
|
node.IterateAttributes(func(key, value string) {
|
||||||
|
v, ok := mExp[key]
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, value, v)
|
||||||
|
delete(mExp, key)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("non unique bucket keys", func(t *testing.T) {
|
require.Empty(t, mExp)
|
||||||
good := []string{
|
}
|
||||||
"StorageType:HDD/RPM:7200",
|
|
||||||
"StorageType:HDD/SMR:True",
|
|
||||||
}
|
|
||||||
_, err := attributes.ParseV2Attributes(good, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
bad := append(good, "StorageType:SSD/Cell:QLC")
|
func TestParseV2Attributes(t *testing.T) {
|
||||||
_, err = attributes.ParseV2Attributes(bad, nil)
|
t.Run("empty", func(t *testing.T) {
|
||||||
|
var node netmap.NodeInfo
|
||||||
|
err := attributes.ReadNodeAttributes(&node, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Zero(t, node.NumberOfAttributes())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty key and/or value", func(t *testing.T) {
|
||||||
|
var node netmap.NodeInfo
|
||||||
|
err := attributes.ReadNodeAttributes(&node, []string{
|
||||||
|
":HDD",
|
||||||
|
})
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
err = attributes.ReadNodeAttributes(&node, []string{
|
||||||
|
"StorageType:",
|
||||||
|
})
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
err = attributes.ReadNodeAttributes(&node, []string{
|
||||||
|
":",
|
||||||
|
})
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("non-unique keys", func(t *testing.T) {
|
||||||
|
var node netmap.NodeInfo
|
||||||
|
err := attributes.ReadNodeAttributes(&node, []string{
|
||||||
|
"StorageType:HDD",
|
||||||
|
"StorageType:HDD",
|
||||||
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("malformed", func(t *testing.T) {
|
t.Run("malformed", func(t *testing.T) {
|
||||||
_, err := attributes.ParseV2Attributes([]string{"..."}, nil)
|
var node netmap.NodeInfo
|
||||||
|
err := attributes.ReadNodeAttributes(&node, []string{"..."})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
_, err = attributes.ParseV2Attributes([]string{"a:b", ""}, nil)
|
err = attributes.ReadNodeAttributes(&node, []string{"a:b", ""})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
_, err = attributes.ParseV2Attributes([]string{"//"}, nil)
|
err = attributes.ReadNodeAttributes(&node, []string{"//"})
|
||||||
require.Error(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("unexpected", func(t *testing.T) {
|
|
||||||
unexpectedBucket := []string{
|
|
||||||
"Location:Europe/City:Moscow",
|
|
||||||
"Price:100",
|
|
||||||
}
|
|
||||||
_, err := attributes.ParseV2Attributes(unexpectedBucket, []string{"Price"})
|
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("correct", func(t *testing.T) {
|
t.Run("correct", func(t *testing.T) {
|
||||||
from := []string{
|
testAttributeMap(t, map[string]string{
|
||||||
"/Location:Europe/Country:Sweden/City:Stockholm",
|
"Location": "Europe",
|
||||||
"/StorageType:HDD/RPM:7200",
|
"StorageType": "HDD",
|
||||||
}
|
}, nil)
|
||||||
attrs, err := attributes.ParseV2Attributes(from, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, attrs, 5)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("escape characters", func(t *testing.T) {
|
t.Run("escape characters", func(t *testing.T) {
|
||||||
from := []string{
|
testAttributeMap(t, map[string]string{
|
||||||
`/K\:ey1:V\/alue\\/Ke\/y2:Va\:lue`,
|
`K\:ey1`: `V\/alue`,
|
||||||
}
|
`Ke\/y2`: `Va\:lue`,
|
||||||
attrs, err := attributes.ParseV2Attributes(from, nil)
|
}, map[string]string{
|
||||||
require.NoError(t, err)
|
`K:ey1`: `V\/alue`,
|
||||||
require.Equal(t, `K:ey1`, attrs[0].Key())
|
`Ke\/y2`: `Va:lue`,
|
||||||
require.Equal(t, `V/alue\`, attrs[0].Value())
|
|
||||||
require.Equal(t, `Ke/y2`, attrs[1].Key())
|
|
||||||
require.Equal(t, `Va:lue`, attrs[1].Value())
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("same attributes", func(t *testing.T) {
|
|
||||||
from := []string{"/a:b", "/a:b"}
|
|
||||||
attrs, err := attributes.ParseV2Attributes(from, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, attrs, 1)
|
|
||||||
|
|
||||||
t.Run("with escape characters", func(t *testing.T) {
|
|
||||||
from = []string{`/a\::b\/`, `/a\::b\/`}
|
|
||||||
attrs, err := attributes.ParseV2Attributes(from, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, attrs, 1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("multiple parents", func(t *testing.T) {
|
|
||||||
from := []string{
|
|
||||||
"/parent1:x/child:x",
|
|
||||||
"/parent2:x/child:x",
|
|
||||||
"/parent2:x/child:x/subchild:x",
|
|
||||||
}
|
|
||||||
attrs, err := attributes.ParseV2Attributes(from, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
var flag bool
|
|
||||||
for _, attr := range attrs {
|
|
||||||
if attr.Key() == "child" {
|
|
||||||
flag = true
|
|
||||||
require.Equal(t, []string{"parent1", "parent2"}, attr.ParentKeys())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
require.True(t, flag)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("consistent order in chain", func(t *testing.T) {
|
|
||||||
from := []string{"/a:1/b:2/c:3"}
|
|
||||||
|
|
||||||
for i := 0; i < 10000; i++ {
|
|
||||||
attrs, err := attributes.ParseV2Attributes(from, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(t, "a", attrs[0].Key())
|
|
||||||
require.Equal(t, "1", attrs[0].Value())
|
|
||||||
require.Equal(t, "b", attrs[1].Key())
|
|
||||||
require.Equal(t, "2", attrs[1].Value())
|
|
||||||
require.Equal(t, "c", attrs[2].Key())
|
|
||||||
require.Equal(t, "3", attrs[2].Value())
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue