forked from TrueCloudLab/frostfs-node
[#1556] Upgrade NeoFS SDK Go with changed container API
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
f699e82ea7
commit
c165d1a9b5
36 changed files with 203 additions and 476 deletions
|
@ -123,7 +123,7 @@ type GetContainerRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container returns structured of the requested container.
|
// Container returns structured of the requested container.
|
||||||
func (x GetContainerRes) Container() *container.Container {
|
func (x GetContainerRes) Container() container.Container {
|
||||||
return x.cliRes.Container()
|
return x.cliRes.Container()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
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"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
@ -19,13 +17,11 @@ import (
|
||||||
"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"
|
||||||
versionSDK "github.com/nspcc-dev/neofs-sdk-go/version"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
containerACL string
|
containerACL string
|
||||||
containerNonce string
|
|
||||||
containerPolicy string
|
containerPolicy string
|
||||||
containerAttributes []string
|
containerAttributes []string
|
||||||
containerAwait bool
|
containerAwait bool
|
||||||
|
@ -52,18 +48,17 @@ It will be stored in sidechain when inner ring will accepts it.`,
|
||||||
placementPolicy.RestrictSubnet(subnetID)
|
placementPolicy.RestrictSubnet(subnetID)
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes, err := parseAttributes(containerAttributes)
|
var cnr container.Container
|
||||||
|
cnr.Init()
|
||||||
|
|
||||||
|
err = parseAttributes(&cnr, containerAttributes)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
var basicACL acl.Basic
|
var basicACL acl.Basic
|
||||||
common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL))
|
common.ExitOnErr(cmd, "decode basic ACL string: %w", basicACL.DecodeString(containerACL))
|
||||||
|
|
||||||
nonce, err := parseNonce(containerNonce)
|
|
||||||
common.ExitOnErr(cmd, "", err)
|
|
||||||
|
|
||||||
key := key.GetOrGenerate(cmd)
|
key := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
cnr := container.New()
|
|
||||||
var tok *session.Container
|
var tok *session.Container
|
||||||
|
|
||||||
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
|
sessionTokenPath, _ := cmd.Flags().GetString(commonflags.SessionToken)
|
||||||
|
@ -72,27 +67,22 @@ It will be stored in sidechain when inner ring will accepts it.`,
|
||||||
common.ReadSessionToken(cmd, tok, sessionTokenPath)
|
common.ReadSessionToken(cmd, tok, sessionTokenPath)
|
||||||
|
|
||||||
issuer := tok.Issuer()
|
issuer := tok.Issuer()
|
||||||
cnr.SetOwnerID(&issuer)
|
cnr.SetOwner(issuer)
|
||||||
} else {
|
} else {
|
||||||
var idOwner user.ID
|
var idOwner user.ID
|
||||||
user.IDFromKey(&idOwner, key.PublicKey)
|
user.IDFromKey(&idOwner, key.PublicKey)
|
||||||
|
|
||||||
cnr.SetOwnerID(&idOwner)
|
cnr.SetOwner(idOwner)
|
||||||
}
|
}
|
||||||
|
|
||||||
ver := versionSDK.Current()
|
cnr.SetPlacementPolicy(*placementPolicy)
|
||||||
|
|
||||||
cnr.SetVersion(&ver)
|
|
||||||
cnr.SetPlacementPolicy(placementPolicy)
|
|
||||||
cnr.SetBasicACL(basicACL)
|
cnr.SetBasicACL(basicACL)
|
||||||
cnr.SetAttributes(attributes)
|
|
||||||
cnr.SetNonceUUID(nonce)
|
|
||||||
|
|
||||||
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
cli := internalclient.GetSDKClientByFlag(cmd, key, commonflags.RPC)
|
||||||
|
|
||||||
var putPrm internalclient.PutContainerPrm
|
var putPrm internalclient.PutContainerPrm
|
||||||
putPrm.SetClient(cli)
|
putPrm.SetClient(cli)
|
||||||
putPrm.SetContainer(*cnr)
|
putPrm.SetContainer(cnr)
|
||||||
|
|
||||||
if tok != nil {
|
if tok != nil {
|
||||||
putPrm.WithinSession(*tok)
|
putPrm.WithinSession(*tok)
|
||||||
|
@ -137,7 +127,6 @@ func initContainerCreateCmd() {
|
||||||
))
|
))
|
||||||
flags.StringVarP(&containerPolicy, "policy", "p", "", "QL-encoded or JSON-encoded placement policy or path to file with it")
|
flags.StringVarP(&containerPolicy, "policy", "p", "", "QL-encoded or JSON-encoded placement policy or path to file with it")
|
||||||
flags.StringSliceVarP(&containerAttributes, "attributes", "a", nil, "comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2")
|
flags.StringSliceVarP(&containerAttributes, "attributes", "a", nil, "comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2")
|
||||||
flags.StringVarP(&containerNonce, "nonce", "n", "", "UUIDv4 nonce value for container")
|
|
||||||
flags.BoolVar(&containerAwait, "await", false, "block execution until container is persisted")
|
flags.BoolVar(&containerAwait, "await", false, "block execution until container is persisted")
|
||||||
flags.StringVar(&containerName, "name", "", "container name attribute")
|
flags.StringVar(&containerName, "name", "", "container name attribute")
|
||||||
flags.BoolVar(&containerNoTimestamp, "disable-timestamp", false, "disable timestamp container attribute")
|
flags.BoolVar(&containerNoTimestamp, "disable-timestamp", false, "disable timestamp container attribute")
|
||||||
|
@ -173,48 +162,23 @@ func parseContainerPolicy(policyString string) (*netmap.PlacementPolicy, error)
|
||||||
return nil, errors.New("can't parse placement policy")
|
return nil, errors.New("can't parse placement policy")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseAttributes(attributes []string) ([]container.Attribute, error) {
|
func parseAttributes(dst *container.Container, attributes []string) error {
|
||||||
result := make([]container.Attribute, len(attributes), len(attributes)+2) // name + timestamp attributes
|
|
||||||
|
|
||||||
for i := range attributes {
|
for i := range attributes {
|
||||||
kvPair := strings.Split(attributes[i], attributeDelimiter)
|
kvPair := strings.Split(attributes[i], attributeDelimiter)
|
||||||
if len(kvPair) != 2 {
|
if len(kvPair) != 2 {
|
||||||
return nil, errors.New("invalid container attribute")
|
return errors.New("invalid container attribute")
|
||||||
}
|
}
|
||||||
|
|
||||||
result[i].SetKey(kvPair[0])
|
dst.SetAttribute(kvPair[0], kvPair[1])
|
||||||
result[i].SetValue(kvPair[1])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !containerNoTimestamp {
|
if !containerNoTimestamp {
|
||||||
index := len(result)
|
container.SetCreationTime(dst, time.Now())
|
||||||
result = append(result, container.Attribute{})
|
|
||||||
result[index].SetKey(container.AttributeTimestamp)
|
|
||||||
result[index].SetValue(strconv.FormatInt(time.Now().Unix(), 10))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if containerName != "" {
|
if containerName != "" {
|
||||||
index := len(result)
|
container.SetName(dst, containerName)
|
||||||
result = append(result, container.Attribute{})
|
|
||||||
result[index].SetKey(container.AttributeName)
|
|
||||||
result[index].SetValue(containerName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
func parseNonce(nonce string) (uuid.UUID, error) {
|
|
||||||
if nonce == "" {
|
|
||||||
result := uuid.New()
|
|
||||||
common.PrintVerbose("Generating container nonce: %s", result)
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
uid, err := uuid.Parse(nonce)
|
|
||||||
if err != nil {
|
|
||||||
return uuid.UUID{}, fmt.Errorf("could not parse nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return uid, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ 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/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,13 +27,12 @@ var getContainerInfoCmd = &cobra.Command{
|
||||||
Short: "Get container field info",
|
Short: "Get container field info",
|
||||||
Long: `Get container field info`,
|
Long: `Get container field info`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
var cnr *container.Container
|
var cnr container.Container
|
||||||
|
|
||||||
if containerPathFrom != "" {
|
if containerPathFrom != "" {
|
||||||
data, err := os.ReadFile(containerPathFrom)
|
data, err := os.ReadFile(containerPathFrom)
|
||||||
common.ExitOnErr(cmd, "can't read file: %w", err)
|
common.ExitOnErr(cmd, "can't read file: %w", err)
|
||||||
|
|
||||||
cnr = container.New()
|
|
||||||
err = cnr.Unmarshal(data)
|
err = cnr.Unmarshal(data)
|
||||||
common.ExitOnErr(cmd, "can't unmarshal container: %w", err)
|
common.ExitOnErr(cmd, "can't unmarshal container: %w", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,8 +62,7 @@ var getContainerInfoCmd = &cobra.Command{
|
||||||
data, err = cnr.MarshalJSON()
|
data, err = cnr.MarshalJSON()
|
||||||
common.ExitOnErr(cmd, "can't JSON encode container: %w", err)
|
common.ExitOnErr(cmd, "can't JSON encode container: %w", err)
|
||||||
} else {
|
} else {
|
||||||
data, err = cnr.Marshal()
|
data = cnr.Marshal()
|
||||||
common.ExitOnErr(cmd, "can't binary encode container: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.WriteFile(containerPathTo, data, 0644)
|
err = os.WriteFile(containerPathTo, data, 0644)
|
||||||
|
@ -90,11 +89,7 @@ func (x *stringWriter) WriteString(s string) (n int, err error) {
|
||||||
return len(s), nil
|
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 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if jsonEncoding {
|
if jsonEncoding {
|
||||||
data, err := cnr.MarshalJSON()
|
data, err := cnr.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -111,45 +106,25 @@ func prettyPrintContainer(cmd *cobra.Command, cnr *container.Container, jsonEnco
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := container.CalculateID(cnr)
|
var id cid.ID
|
||||||
|
container.CalculateID(&id, cnr)
|
||||||
cmd.Println("container ID:", id)
|
cmd.Println("container ID:", id)
|
||||||
|
|
||||||
v := cnr.Version()
|
cmd.Println("owner ID:", cnr.Owner())
|
||||||
cmd.Printf("version: %d.%d\n", v.Major(), v.Minor())
|
|
||||||
|
|
||||||
cmd.Println("owner ID:", cnr.OwnerID())
|
|
||||||
|
|
||||||
basicACL := cnr.BasicACL()
|
basicACL := cnr.BasicACL()
|
||||||
prettyPrintBasicACL(cmd, basicACL)
|
prettyPrintBasicACL(cmd, basicACL)
|
||||||
|
|
||||||
for _, attribute := range cnr.Attributes() {
|
cmd.Println("created:", container.CreatedAt(cnr))
|
||||||
if attribute.Key() == container.AttributeTimestamp {
|
|
||||||
cmd.Printf("attribute: %s=%s (%s)\n",
|
|
||||||
attribute.Key(),
|
|
||||||
attribute.Value(),
|
|
||||||
common.PrettyPrintUnixTime(attribute.Value()))
|
|
||||||
|
|
||||||
continue
|
cmd.Println("attributes:")
|
||||||
}
|
cnr.IterateAttributes(func(key, val string) {
|
||||||
|
cmd.Printf("\t%s=%s\n", key, val)
|
||||||
|
})
|
||||||
|
|
||||||
cmd.Printf("attribute: %s=%s\n", attribute.Key(), attribute.Value())
|
|
||||||
}
|
|
||||||
|
|
||||||
nonce, err := cnr.NonceUUID()
|
|
||||||
if err == nil {
|
|
||||||
cmd.Println("nonce:", nonce)
|
|
||||||
} else {
|
|
||||||
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:")
|
||||||
common.ExitOnErr(cmd, "write policy: %w", pp.WriteStringTo((*stringWriter)(cmd)))
|
common.ExitOnErr(cmd, "write policy: %w", cnr.PlacementPolicy().WriteStringTo((*stringWriter)(cmd)))
|
||||||
cmd.Println()
|
cmd.Println()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.Basic) {
|
func prettyPrintBasicACL(cmd *cobra.Command, basicACL acl.Basic) {
|
||||||
|
|
|
@ -213,16 +213,11 @@ type morphLoadWriter struct {
|
||||||
key []byte
|
key []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *morphLoadWriter) Put(a containerSDK.UsedSpaceAnnouncement) error {
|
func (w *morphLoadWriter) Put(a containerSDK.SizeEstimation) error {
|
||||||
cnr, ok := a.ContainerID()
|
|
||||||
if !ok {
|
|
||||||
return errors.New("missing container ID in load announcement")
|
|
||||||
}
|
|
||||||
|
|
||||||
w.log.Debug("save used space announcement in contract",
|
w.log.Debug("save used space announcement in contract",
|
||||||
zap.Uint64("epoch", a.Epoch()),
|
zap.Uint64("epoch", a.Epoch()),
|
||||||
zap.Stringer("cid", cnr),
|
zap.Stringer("cid", a.Container()),
|
||||||
zap.Uint64("size", a.UsedSpace()),
|
zap.Uint64("size", a.Value()),
|
||||||
)
|
)
|
||||||
|
|
||||||
prm := cntClient.AnnounceLoadPrm{}
|
prm := cntClient.AnnounceLoadPrm{}
|
||||||
|
@ -239,7 +234,7 @@ func (*morphLoadWriter) Close() error {
|
||||||
|
|
||||||
type nopLoadWriter struct{}
|
type nopLoadWriter struct{}
|
||||||
|
|
||||||
func (nopLoadWriter) Put(containerSDK.UsedSpaceAnnouncement) error {
|
func (nopLoadWriter) Put(containerSDK.SizeEstimation) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,10 +297,10 @@ type remoteLoadAnnounceWriter struct {
|
||||||
|
|
||||||
client client.Client
|
client client.Client
|
||||||
|
|
||||||
buf []containerSDK.UsedSpaceAnnouncement
|
buf []containerSDK.SizeEstimation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *remoteLoadAnnounceWriter) Put(a containerSDK.UsedSpaceAnnouncement) error {
|
func (r *remoteLoadAnnounceWriter) Put(a containerSDK.SizeEstimation) error {
|
||||||
r.buf = append(r.buf, a)
|
r.buf = append(r.buf, a)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -354,11 +349,6 @@ func (l *loadPlacementBuilder) buildPlacement(epoch uint64, idCnr cid.ID) ([][]n
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
policy := cnr.Value.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)
|
||||||
|
@ -367,7 +357,7 @@ func (l *loadPlacementBuilder) buildPlacement(epoch uint64, idCnr cid.ID) ([][]n
|
||||||
binCnr := make([]byte, sha256.Size)
|
binCnr := make([]byte, sha256.Size)
|
||||||
idCnr.Encode(binCnr)
|
idCnr.Encode(binCnr)
|
||||||
|
|
||||||
cnrNodes, err := nm.ContainerNodes(*policy, binCnr)
|
cnrNodes, err := nm.ContainerNodes(cnr.Value.PlacementPolicy(), 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)
|
||||||
}
|
}
|
||||||
|
@ -403,15 +393,15 @@ func (d *localStorageLoad) Iterate(f loadcontroller.UsedSpaceFilter, h loadcontr
|
||||||
zap.Stringer("cid", idList[i]),
|
zap.Stringer("cid", idList[i]),
|
||||||
)
|
)
|
||||||
|
|
||||||
a := containerSDK.NewAnnouncement()
|
var a containerSDK.SizeEstimation
|
||||||
a.SetContainerID(idList[i])
|
a.SetContainer(idList[i])
|
||||||
a.SetUsedSpace(sz)
|
a.SetValue(sz)
|
||||||
|
|
||||||
if f != nil && !f(*a) {
|
if f != nil && !f(a) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h(*a); err != nil {
|
if err := h(a); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,8 +469,15 @@ func (c *usedSpaceService) AnnounceUsedSpace(ctx context.Context, req *container
|
||||||
return nil, fmt.Errorf("could not initialize container's used space writer: %w", err)
|
return nil, fmt.Errorf("could not initialize container's used space writer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var est containerSDK.SizeEstimation
|
||||||
|
|
||||||
for _, aV2 := range req.GetBody().GetAnnouncements() {
|
for _, aV2 := range req.GetBody().GetAnnouncements() {
|
||||||
if err := c.processLoadValue(ctx, *containerSDK.NewAnnouncementFromV2(&aV2), passedRoute, w); err != nil {
|
err = est.ReadFromV2(aV2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid size announcement: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.processLoadValue(ctx, est, passedRoute, w); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,14 +524,9 @@ func (l *loadPlacementBuilder) isNodeFromContainerKey(epoch uint64, cnr cid.ID,
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *usedSpaceService) processLoadValue(_ context.Context, a containerSDK.UsedSpaceAnnouncement,
|
func (c *usedSpaceService) processLoadValue(_ context.Context, a containerSDK.SizeEstimation,
|
||||||
route []loadroute.ServerInfo, w loadcontroller.Writer) error {
|
route []loadroute.ServerInfo, w loadcontroller.Writer) error {
|
||||||
cnr, ok := a.ContainerID()
|
fromCnr, err := c.loadPlacementBuilder.isNodeFromContainerKey(a.Epoch(), a.Container(), route[0].PublicKey())
|
||||||
if !ok {
|
|
||||||
return errors.New("missing container ID in load announcement")
|
|
||||||
}
|
|
||||||
|
|
||||||
fromCnr, err := c.loadPlacementBuilder.isNodeFromContainerKey(a.Epoch(), cnr, route[0].PublicKey())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not verify that the sender belongs to the container: %w", err)
|
return fmt.Errorf("could not verify that the sender belongs to the container: %w", err)
|
||||||
} else if !fromCnr {
|
} else if !fromCnr {
|
||||||
|
@ -591,13 +583,8 @@ func (m morphContainerWriter) Put(cnr containerCore.Container) (*cid.ID, error)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
idOwner := cnr.Value.OwnerID()
|
|
||||||
if idOwner == nil {
|
|
||||||
return nil, errors.New("missing container owner")
|
|
||||||
}
|
|
||||||
|
|
||||||
if m.cacheEnabled {
|
if m.cacheEnabled {
|
||||||
m.lists.InvalidateContainerList(*idOwner)
|
m.lists.InvalidateContainerList(cnr.Value.Owner())
|
||||||
}
|
}
|
||||||
|
|
||||||
return containerID, nil
|
return containerID, nil
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -17,9 +17,9 @@ require (
|
||||||
github.com/nspcc-dev/hrw v1.0.9
|
github.com/nspcc-dev/hrw v1.0.9
|
||||||
github.com/nspcc-dev/neo-go v0.99.1-pre.0.20220609082921-2c9fb2044242
|
github.com/nspcc-dev/neo-go v0.99.1-pre.0.20220609082921-2c9fb2044242
|
||||||
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.3-0.20220621170933-dd233c3fbc84
|
github.com/nspcc-dev/neofs-api-go/v2 v2.12.3-0.20220630100506-c6f7ab3ef1bf
|
||||||
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.20220623080532-aa5ee1dcde1c
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.4.0.20220704082116-2ad89085a341
|
||||||
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.
|
@ -1,54 +0,0 @@
|
||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/version"
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errNilPolicy = errors.New("placement policy is nil")
|
|
||||||
errRepeatedAttributes = errors.New("repeated attributes found")
|
|
||||||
errEmptyAttribute = errors.New("empty attribute found")
|
|
||||||
)
|
|
||||||
|
|
||||||
// CheckFormat conducts an initial check of the v2 container data.
|
|
||||||
//
|
|
||||||
// It is expected that if a container fails this test,
|
|
||||||
// it will not be approved by the inner ring.
|
|
||||||
func CheckFormat(c *container.Container) error {
|
|
||||||
if c.PlacementPolicy() == nil {
|
|
||||||
return errNilPolicy
|
|
||||||
}
|
|
||||||
|
|
||||||
if v := c.Version(); v == nil || !version.IsValid(*v) {
|
|
||||||
return fmt.Errorf("incorrect version %s", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.OwnerID() == nil {
|
|
||||||
return errors.New("missing owner")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := c.NonceUUID(); err != nil {
|
|
||||||
return fmt.Errorf("incorrect nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if there are repeated attributes
|
|
||||||
attrs := c.Attributes()
|
|
||||||
uniqueAttr := make(map[string]struct{}, len(attrs))
|
|
||||||
for _, attr := range attrs {
|
|
||||||
if _, exists := uniqueAttr[attr.Key()]; exists {
|
|
||||||
return errRepeatedAttributes
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr.Value() == "" {
|
|
||||||
return errEmptyAttribute
|
|
||||||
}
|
|
||||||
|
|
||||||
uniqueAttr[attr.Key()] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/test"
|
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
|
||||||
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/version"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCheckFormat(t *testing.T) {
|
|
||||||
c := container.New()
|
|
||||||
|
|
||||||
require.Error(t, CheckFormat(c))
|
|
||||||
|
|
||||||
policy := netmaptest.PlacementPolicy()
|
|
||||||
c.SetPlacementPolicy(&policy)
|
|
||||||
|
|
||||||
require.Error(t, CheckFormat(c))
|
|
||||||
|
|
||||||
ver := version.Current()
|
|
||||||
c.SetVersion(&ver)
|
|
||||||
|
|
||||||
require.Error(t, CheckFormat(c))
|
|
||||||
|
|
||||||
var idUser user.ID
|
|
||||||
user.IDFromKey(&idUser, test.DecodeKey(-1).PublicKey)
|
|
||||||
|
|
||||||
c.SetOwnerID(&idUser)
|
|
||||||
|
|
||||||
// set incorrect nonce
|
|
||||||
cV2 := c.ToV2()
|
|
||||||
cV2.SetNonce([]byte{1, 2, 3})
|
|
||||||
c = container.NewContainerFromV2(cV2)
|
|
||||||
|
|
||||||
require.Error(t, CheckFormat(c))
|
|
||||||
|
|
||||||
c.SetNonceUUID(uuid.New())
|
|
||||||
|
|
||||||
require.NoError(t, CheckFormat(c))
|
|
||||||
|
|
||||||
// set empty value attribute
|
|
||||||
var attr1 container.Attribute
|
|
||||||
attr1.SetKey("attr")
|
|
||||||
attrs := container.Attributes{attr1}
|
|
||||||
|
|
||||||
c.SetAttributes(attrs)
|
|
||||||
|
|
||||||
require.ErrorIs(t, CheckFormat(c), errEmptyAttribute)
|
|
||||||
|
|
||||||
// add same key attribute
|
|
||||||
var attr2 container.Attribute
|
|
||||||
attr2.SetKey(attr1.Key())
|
|
||||||
attr2.SetValue("val")
|
|
||||||
|
|
||||||
attrs[0].SetValue(attr2.Value())
|
|
||||||
|
|
||||||
attrs = append(attrs, attr2)
|
|
||||||
|
|
||||||
c.SetAttributes(attrs)
|
|
||||||
|
|
||||||
require.ErrorIs(t, CheckFormat(c), errRepeatedAttributes)
|
|
||||||
|
|
||||||
attrs[1].SetKey(attr1.Key() + "smth")
|
|
||||||
|
|
||||||
c.SetAttributes(attrs)
|
|
||||||
|
|
||||||
require.NoError(t, CheckFormat(c))
|
|
||||||
}
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
// Container groups information about the NeoFS container stored in the NeoFS network.
|
// Container groups information about the NeoFS container stored in the NeoFS network.
|
||||||
type Container struct {
|
type Container struct {
|
||||||
// Container structure.
|
// Container structure.
|
||||||
Value *container.Container
|
Value container.Container
|
||||||
|
|
||||||
// Signature of the Value.
|
// Signature of the Value.
|
||||||
Signature neofscrypto.Signature
|
Signature neofscrypto.Signature
|
||||||
|
|
|
@ -60,19 +60,10 @@ func (ap *Processor) processStartAudit(epoch uint64) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
policy := cnr.Value.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.ContainerNodes(*policy, pivot)
|
nodes, err := nm.ContainerNodes(cnr.Value.PlacementPolicy(), 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]),
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||||
morphsubnet "github.com/nspcc-dev/neofs-node/pkg/morph/client/subnet"
|
morphsubnet "github.com/nspcc-dev/neofs-node/pkg/morph/client/subnet"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
||||||
|
@ -30,7 +28,7 @@ type putEvent interface {
|
||||||
type putContainerContext struct {
|
type putContainerContext struct {
|
||||||
e putEvent
|
e putEvent
|
||||||
|
|
||||||
name, zone string // from container structure
|
d containerSDK.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process a new container from the user by checking the container sanity
|
// Process a new container from the user by checking the container sanity
|
||||||
|
@ -59,21 +57,15 @@ func (cp *Processor) processContainerPut(put putEvent) {
|
||||||
|
|
||||||
func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
||||||
binCnr := ctx.e.Container()
|
binCnr := ctx.e.Container()
|
||||||
|
var cnr containerSDK.Container
|
||||||
cnr := containerSDK.New()
|
|
||||||
|
|
||||||
err := cnr.Unmarshal(binCnr)
|
err := cnr.Unmarshal(binCnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid binary container: %w", err)
|
return fmt.Errorf("invalid binary container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ownerContainer := cnr.OwnerID()
|
|
||||||
if ownerContainer == nil {
|
|
||||||
return errors.New("missing container owner")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cp.verifySignature(signatureVerificationData{
|
err = cp.verifySignature(signatureVerificationData{
|
||||||
ownerContainer: *ownerContainer,
|
ownerContainer: cnr.Owner(),
|
||||||
verb: session.VerbContainerPut,
|
verb: session.VerbContainerPut,
|
||||||
binTokenSession: ctx.e.SessionToken(),
|
binTokenSession: ctx.e.SessionToken(),
|
||||||
binPublicKey: ctx.e.PublicKey(),
|
binPublicKey: ctx.e.PublicKey(),
|
||||||
|
@ -96,12 +88,6 @@ func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
||||||
return fmt.Errorf("NNS: %w", err)
|
return fmt.Errorf("NNS: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform format check
|
|
||||||
err = container.CheckFormat(cnr)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("incorrect container format: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,8 +102,8 @@ func (cp *Processor) approvePutContainer(ctx *putContainerContext) {
|
||||||
prm.SetKey(e.PublicKey())
|
prm.SetKey(e.PublicKey())
|
||||||
prm.SetSignature(e.Signature())
|
prm.SetSignature(e.Signature())
|
||||||
prm.SetToken(e.SessionToken())
|
prm.SetToken(e.SessionToken())
|
||||||
prm.SetName(ctx.name)
|
prm.SetName(ctx.d.Name())
|
||||||
prm.SetZone(ctx.zone)
|
prm.SetZone(ctx.d.Zone())
|
||||||
|
|
||||||
if nr := e.NotaryRequest(); nr != nil {
|
if nr := e.NotaryRequest(); nr != nil {
|
||||||
// put event was received via Notary service
|
// put event was received via Notary service
|
||||||
|
@ -169,13 +155,8 @@ func (cp *Processor) checkDeleteContainer(e *containerEvent.Delete) error {
|
||||||
return fmt.Errorf("could not receive the container: %w", err)
|
return fmt.Errorf("could not receive the container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ownerContainer := cnr.Value.OwnerID()
|
|
||||||
if ownerContainer == nil {
|
|
||||||
return errors.New("missing container owner")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cp.verifySignature(signatureVerificationData{
|
err = cp.verifySignature(signatureVerificationData{
|
||||||
ownerContainer: *ownerContainer,
|
ownerContainer: cnr.Value.Owner(),
|
||||||
verb: session.VerbContainerDelete,
|
verb: session.VerbContainerDelete,
|
||||||
idContainerSet: true,
|
idContainerSet: true,
|
||||||
idContainer: idCnr,
|
idContainer: idCnr,
|
||||||
|
@ -213,47 +194,37 @@ func (cp *Processor) approveDeleteContainer(e *containerEvent.Delete) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkNNS(ctx *putContainerContext, cnr *containerSDK.Container) error {
|
func checkNNS(ctx *putContainerContext, cnr containerSDK.Container) error {
|
||||||
// fetch native name and zone
|
// fetch domain info
|
||||||
ctx.name, ctx.zone = containerSDK.GetNativeNameWithZone(cnr)
|
ctx.d = containerSDK.ReadDomain(cnr)
|
||||||
|
|
||||||
// if PutNamed event => check if values in container correspond to args
|
// if PutNamed event => check if values in container correspond to args
|
||||||
if named, ok := ctx.e.(interface {
|
if named, ok := ctx.e.(interface {
|
||||||
Name() string
|
Name() string
|
||||||
Zone() string
|
Zone() string
|
||||||
}); ok {
|
}); ok {
|
||||||
if name := named.Name(); name != ctx.name {
|
if name := named.Name(); name != ctx.d.Name() {
|
||||||
return fmt.Errorf("names differ %s/%s", name, ctx.name)
|
return fmt.Errorf("names differ %s/%s", name, ctx.d.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
if zone := named.Zone(); zone != ctx.zone {
|
if zone := named.Zone(); zone != ctx.d.Zone() {
|
||||||
return fmt.Errorf("zones differ %s/%s", zone, ctx.zone)
|
return fmt.Errorf("zones differ %s/%s", zone, ctx.d.Zone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkSubnet(subCli *morphsubnet.Client, cnr *containerSDK.Container) error {
|
func checkSubnet(subCli *morphsubnet.Client, cnr containerSDK.Container) error {
|
||||||
owner := cnr.OwnerID()
|
|
||||||
if owner == nil {
|
|
||||||
return errors.New("missing owner")
|
|
||||||
}
|
|
||||||
|
|
||||||
policy := cnr.PlacementPolicy()
|
|
||||||
if policy == nil {
|
|
||||||
return errors.New("missing placement policy")
|
|
||||||
}
|
|
||||||
|
|
||||||
prm := morphsubnet.UserAllowedPrm{}
|
prm := morphsubnet.UserAllowedPrm{}
|
||||||
|
|
||||||
subID := policy.Subnet()
|
subID := cnr.PlacementPolicy().Subnet()
|
||||||
if subnetid.IsZero(subID) {
|
if subnetid.IsZero(subID) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
prm.SetID(subID.Marshal())
|
prm.SetID(subID.Marshal())
|
||||||
prm.SetClient(owner.WalletBytes())
|
prm.SetClient(cnr.Owner().WalletBytes())
|
||||||
|
|
||||||
res, err := subCli.UserAllowed(prm)
|
res, err := subCli.UserAllowed(prm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -56,13 +56,8 @@ func (cp *Processor) checkSetEACL(e container.SetEACL) error {
|
||||||
return errors.New("ACL extension disabled by container basic ACL")
|
return errors.New("ACL extension disabled by container basic ACL")
|
||||||
}
|
}
|
||||||
|
|
||||||
ownerContainer := cnr.Value.OwnerID()
|
|
||||||
if ownerContainer == nil {
|
|
||||||
return errors.New("missing container owner")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cp.verifySignature(signatureVerificationData{
|
err = cp.verifySignature(signatureVerificationData{
|
||||||
ownerContainer: *ownerContainer,
|
ownerContainer: cnr.Value.Owner(),
|
||||||
verb: session.VerbContainerSetEACL,
|
verb: session.VerbContainerSetEACL,
|
||||||
idContainerSet: true,
|
idContainerSet: true,
|
||||||
idContainer: idCnr,
|
idContainer: idCnr,
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
@ -93,8 +92,8 @@ 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 {
|
||||||
return *(*containerAPI.Container)(c).OwnerID()
|
return (containerAPI.Container)(c).Owner()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s settlementDeps) AuditResultsForEpoch(epoch uint64) ([]*auditAPI.Result, error) {
|
func (s settlementDeps) AuditResultsForEpoch(epoch uint64) ([]*auditAPI.Result, error) {
|
||||||
|
@ -123,7 +122,7 @@ func (s settlementDeps) ContainerInfo(cid cid.ID) (common.ContainerInfo, error)
|
||||||
return nil, fmt.Errorf("could not get container from storage: %w", err)
|
return nil, fmt.Errorf("could not get container from storage: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (*containerWrapper)(cnr.Value), nil
|
return (containerWrapper)(cnr.Value), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s settlementDeps) buildContainer(e uint64, cid cid.ID) ([][]netmapAPI.NodeInfo, *netmapAPI.NetMap, error) {
|
func (s settlementDeps) buildContainer(e uint64, cid cid.ID) ([][]netmapAPI.NodeInfo, *netmapAPI.NetMap, error) {
|
||||||
|
@ -147,16 +146,11 @@ func (s settlementDeps) buildContainer(e uint64, cid cid.ID) ([][]netmapAPI.Node
|
||||||
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.Value.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.ContainerNodes(
|
cn, err := nm.ContainerNodes(
|
||||||
*policy,
|
cnr.Value.PlacementPolicy(),
|
||||||
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 {
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
core "github.com/nspcc-dev/neofs-node/pkg/core/container"
|
core "github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
||||||
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
"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"
|
||||||
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
|
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
@ -90,7 +89,6 @@ func (c *Client) Get(cid []byte) (*containercore.Container, error) {
|
||||||
|
|
||||||
var cnr containercore.Container
|
var cnr containercore.Container
|
||||||
|
|
||||||
cnr.Value = container.New()
|
|
||||||
if err := cnr.Value.Unmarshal(cnrBytes); err != nil {
|
if err := cnr.Value.Unmarshal(cnrBytes); err != nil {
|
||||||
// use other major version if there any
|
// use other major version if there any
|
||||||
return nil, fmt.Errorf("can't unmarshal container: %w", err)
|
return nil, fmt.Errorf("can't unmarshal container: %w", err)
|
||||||
|
|
|
@ -2,7 +2,6 @@ package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
v2refs "github.com/nspcc-dev/neofs-api-go/v2/refs"
|
v2refs "github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
@ -13,14 +12,14 @@ import (
|
||||||
|
|
||||||
// AnnounceLoadPrm groups parameters of AnnounceLoad operation.
|
// AnnounceLoadPrm groups parameters of AnnounceLoad operation.
|
||||||
type AnnounceLoadPrm struct {
|
type AnnounceLoadPrm struct {
|
||||||
a container.UsedSpaceAnnouncement
|
a container.SizeEstimation
|
||||||
key []byte
|
key []byte
|
||||||
|
|
||||||
client.InvokePrmOptional
|
client.InvokePrmOptional
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAnnouncement sets announcement.
|
// SetAnnouncement sets announcement.
|
||||||
func (a2 *AnnounceLoadPrm) SetAnnouncement(a container.UsedSpaceAnnouncement) {
|
func (a2 *AnnounceLoadPrm) SetAnnouncement(a container.SizeEstimation) {
|
||||||
a2.a = a
|
a2.a = a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,17 +33,12 @@ func (a2 *AnnounceLoadPrm) SetReporter(key []byte) {
|
||||||
//
|
//
|
||||||
// Returns any error encountered that caused the saving to interrupt.
|
// Returns any error encountered that caused the saving to interrupt.
|
||||||
func (c *Client) AnnounceLoad(p AnnounceLoadPrm) error {
|
func (c *Client) AnnounceLoad(p AnnounceLoadPrm) error {
|
||||||
cnr, ok := p.a.ContainerID()
|
|
||||||
if !ok {
|
|
||||||
return errors.New("missing container for load announcement")
|
|
||||||
}
|
|
||||||
|
|
||||||
binCnr := make([]byte, sha256.Size)
|
binCnr := make([]byte, sha256.Size)
|
||||||
cnr.Encode(binCnr)
|
p.a.Container().Encode(binCnr)
|
||||||
|
|
||||||
prm := client.InvokePrm{}
|
prm := client.InvokePrm{}
|
||||||
prm.SetMethod(putSizeMethod)
|
prm.SetMethod(putSizeMethod)
|
||||||
prm.SetArgs(p.a.Epoch(), binCnr, p.a.UsedSpace(), p.key)
|
prm.SetArgs(p.a.Epoch(), binCnr, p.a.Value(), p.key)
|
||||||
prm.InvokePrmOptional = p.InvokePrmOptional
|
prm.InvokePrmOptional = p.InvokePrmOptional
|
||||||
|
|
||||||
err := c.client.Invoke(prm)
|
err := c.client.Invoke(prm)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
@ -16,21 +15,14 @@ import (
|
||||||
//
|
//
|
||||||
// Returns error if container is nil.
|
// Returns error if container is nil.
|
||||||
func Put(c *Client, cnr containercore.Container) (*cid.ID, error) {
|
func Put(c *Client, cnr containercore.Container) (*cid.ID, error) {
|
||||||
if cnr.Value == nil {
|
data := cnr.Value.Marshal()
|
||||||
return nil, errNilArgument
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := cnr.Value.Marshal()
|
d := container.ReadDomain(cnr.Value)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("can't marshal container: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
name, zone := container.GetNativeNameWithZone(cnr.Value)
|
|
||||||
|
|
||||||
var prm PutPrm
|
var prm PutPrm
|
||||||
prm.SetContainer(data)
|
prm.SetContainer(data)
|
||||||
prm.SetName(name)
|
prm.SetName(d.Name())
|
||||||
prm.SetZone(zone)
|
prm.SetZone(d.Zone())
|
||||||
|
|
||||||
if cnr.Session != nil {
|
if cnr.Session != nil {
|
||||||
prm.SetToken(cnr.Session.Marshal())
|
prm.SetToken(cnr.Session.Marshal())
|
||||||
|
@ -43,13 +35,13 @@ func Put(c *Client, cnr containercore.Container) (*cid.ID, error) {
|
||||||
prm.SetKey(sigV2.GetKey())
|
prm.SetKey(sigV2.GetKey())
|
||||||
prm.SetSignature(sigV2.GetSign())
|
prm.SetSignature(sigV2.GetSign())
|
||||||
|
|
||||||
err = c.Put(prm)
|
err := c.Put(prm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var id cid.ID
|
var id cid.ID
|
||||||
id.SetSHA256(sha256.Sum256(data))
|
container.CalculateIDFromBinary(&id, data)
|
||||||
|
|
||||||
return &id, nil
|
return &id, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ type Task struct {
|
||||||
|
|
||||||
idCnr cid.ID
|
idCnr cid.ID
|
||||||
|
|
||||||
cnr *container.Container
|
cnr container.Container
|
||||||
|
|
||||||
nm *netmap.NetMap
|
nm *netmap.NetMap
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ func (t *Task) ContainerID() cid.ID {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithContainerStructure sets structure of the container under audit.
|
// WithContainerStructure sets structure of the container under audit.
|
||||||
func (t *Task) WithContainerStructure(cnr *container.Container) *Task {
|
func (t *Task) WithContainerStructure(cnr container.Container) *Task {
|
||||||
if t != nil {
|
if t != nil {
|
||||||
t.cnr = cnr
|
t.cnr = cnr
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ func (t *Task) WithContainerStructure(cnr *container.Container) *Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerStructure returns structure of the container under audit.
|
// ContainerStructure returns structure of the container under audit.
|
||||||
func (t *Task) ContainerStructure() *container.Container {
|
func (t *Task) ContainerStructure() container.Container {
|
||||||
return t.cnr
|
return t.cnr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ type announceContext struct {
|
||||||
commonContext
|
commonContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the processing of UsedSpaceAnnouncement values.
|
// Start starts the processing of container.SizeEstimation values.
|
||||||
//
|
//
|
||||||
// Single Start operation overtakes all data from LocalMetrics to
|
// Single Start operation overtakes all data from LocalMetrics to
|
||||||
// LocalAnnouncementTarget (Controller's parameters).
|
// LocalAnnouncementTarget (Controller's parameters).
|
||||||
|
@ -82,10 +82,10 @@ func (c *announceContext) announce() {
|
||||||
|
|
||||||
// iterate over all collected metrics and write them to the target
|
// iterate over all collected metrics and write them to the target
|
||||||
err = metricsIterator.Iterate(
|
err = metricsIterator.Iterate(
|
||||||
func(container.UsedSpaceAnnouncement) bool {
|
func(container.SizeEstimation) bool {
|
||||||
return true // local metrics don't know about epochs
|
return true // local metrics don't know about epochs
|
||||||
},
|
},
|
||||||
func(a container.UsedSpaceAnnouncement) error {
|
func(a container.SizeEstimation) error {
|
||||||
a.SetEpoch(c.epoch) // set epoch explicitly
|
a.SetEpoch(c.epoch) // set epoch explicitly
|
||||||
return targetWriter.Put(a)
|
return targetWriter.Put(a)
|
||||||
},
|
},
|
||||||
|
@ -179,7 +179,7 @@ type stopContext struct {
|
||||||
commonContext
|
commonContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop interrupts the processing of UsedSpaceAnnouncement values.
|
// Stop interrupts the processing of container.SizeEstimation values.
|
||||||
//
|
//
|
||||||
// Single Stop operation releases an announcement context and overtakes
|
// Single Stop operation releases an announcement context and overtakes
|
||||||
// all data from AnnouncementAccumulator to ResultReceiver (Controller's
|
// all data from AnnouncementAccumulator to ResultReceiver (Controller's
|
||||||
|
|
|
@ -19,12 +19,12 @@ type testAnnouncementStorage struct {
|
||||||
|
|
||||||
mtx sync.RWMutex
|
mtx sync.RWMutex
|
||||||
|
|
||||||
m map[uint64][]container.UsedSpaceAnnouncement
|
m map[uint64][]container.SizeEstimation
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestStorage() *testAnnouncementStorage {
|
func newTestStorage() *testAnnouncementStorage {
|
||||||
return &testAnnouncementStorage{
|
return &testAnnouncementStorage{
|
||||||
m: make(map[uint64][]container.UsedSpaceAnnouncement),
|
m: make(map[uint64][]container.SizeEstimation),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ func (s *testAnnouncementStorage) InitWriter(context.Context) (loadcontroller.Wr
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *testAnnouncementStorage) Put(v container.UsedSpaceAnnouncement) error {
|
func (s *testAnnouncementStorage) Put(v container.SizeEstimation) error {
|
||||||
s.mtx.Lock()
|
s.mtx.Lock()
|
||||||
s.m[v.Epoch()] = append(s.m[v.Epoch()], v)
|
s.m[v.Epoch()] = append(s.m[v.Epoch()], v)
|
||||||
s.mtx.Unlock()
|
s.mtx.Unlock()
|
||||||
|
@ -73,12 +73,11 @@ func (s *testAnnouncementStorage) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func randAnnouncement() container.UsedSpaceAnnouncement {
|
func randAnnouncement() (a container.SizeEstimation) {
|
||||||
a := container.NewAnnouncement()
|
a.SetContainer(cidtest.ID())
|
||||||
a.SetContainerID(cidtest.ID())
|
a.SetValue(rand.Uint64())
|
||||||
a.SetUsedSpace(rand.Uint64())
|
|
||||||
|
|
||||||
return *a
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSimpleScenario(t *testing.T) {
|
func TestSimpleScenario(t *testing.T) {
|
||||||
|
@ -116,7 +115,7 @@ func TestSimpleScenario(t *testing.T) {
|
||||||
const goodNum = 4
|
const goodNum = 4
|
||||||
|
|
||||||
// create 2 random values for processing epoch and 1 for some different
|
// create 2 random values for processing epoch and 1 for some different
|
||||||
announces := make([]container.UsedSpaceAnnouncement, 0, goodNum)
|
announces := make([]container.SizeEstimation, 0, goodNum)
|
||||||
|
|
||||||
for i := 0; i < goodNum; i++ {
|
for i := 0; i < goodNum; i++ {
|
||||||
a := randAnnouncement()
|
a := randAnnouncement()
|
||||||
|
@ -174,13 +173,13 @@ func TestSimpleScenario(t *testing.T) {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
// result target should contain all "good" announcements and shoult not container the "bad" one
|
// result target should contain all "good" announcements and shoult not container the "bad" one
|
||||||
var res []container.UsedSpaceAnnouncement
|
var res []container.SizeEstimation
|
||||||
|
|
||||||
err := resultStorage.Iterate(
|
err := resultStorage.Iterate(
|
||||||
func(a container.UsedSpaceAnnouncement) bool {
|
func(a container.SizeEstimation) bool {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
func(a container.UsedSpaceAnnouncement) error {
|
func(a container.SizeEstimation) error {
|
||||||
res = append(res, a)
|
res = append(res, a)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,22 +7,22 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UsedSpaceHandler describes the signature of the UsedSpaceAnnouncement
|
// UsedSpaceHandler describes the signature of the container.SizeEstimation
|
||||||
// value handling function.
|
// value handling function.
|
||||||
//
|
//
|
||||||
// Termination of processing without failures is usually signaled
|
// Termination of processing without failures is usually signaled
|
||||||
// with a zero error, while a specific value may describe the reason
|
// with a zero error, while a specific value may describe the reason
|
||||||
// for failure.
|
// for failure.
|
||||||
type UsedSpaceHandler func(container.UsedSpaceAnnouncement) error
|
type UsedSpaceHandler func(container.SizeEstimation) error
|
||||||
|
|
||||||
// UsedSpaceFilter describes the signature of the function for
|
// UsedSpaceFilter describes the signature of the function for
|
||||||
// checking whether a value meets a certain criterion.
|
// checking whether a value meets a certain criterion.
|
||||||
//
|
//
|
||||||
// Return of true means conformity, false - vice versa.
|
// Return of true means conformity, false - vice versa.
|
||||||
type UsedSpaceFilter func(container.UsedSpaceAnnouncement) bool
|
type UsedSpaceFilter func(container.SizeEstimation) bool
|
||||||
|
|
||||||
// Iterator is a group of methods provided by entity
|
// Iterator is a group of methods provided by entity
|
||||||
// which can iterate over a group of UsedSpaceAnnouncement values.
|
// which can iterate over a group of container.SizeEstimation values.
|
||||||
type Iterator interface {
|
type Iterator interface {
|
||||||
// Iterate must start an iterator over values that
|
// Iterate must start an iterator over values that
|
||||||
// meet the filter criterion (returns true).
|
// meet the filter criterion (returns true).
|
||||||
|
@ -37,7 +37,7 @@ type Iterator interface {
|
||||||
|
|
||||||
// IteratorProvider is a group of methods provided
|
// IteratorProvider is a group of methods provided
|
||||||
// by entity which generates iterators over
|
// by entity which generates iterators over
|
||||||
// UsedSpaceAnnouncement values.
|
// container.SizeEstimation values.
|
||||||
type IteratorProvider interface {
|
type IteratorProvider interface {
|
||||||
// InitIterator should return an initialized Iterator.
|
// InitIterator should return an initialized Iterator.
|
||||||
//
|
//
|
||||||
|
@ -49,12 +49,12 @@ type IteratorProvider interface {
|
||||||
InitIterator(context.Context) (Iterator, error)
|
InitIterator(context.Context) (Iterator, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writer describes the interface for storing UsedSpaceAnnouncement values.
|
// Writer describes the interface for storing container.SizeEstimation values.
|
||||||
//
|
//
|
||||||
// This interface is provided by both local storage
|
// This interface is provided by both local storage
|
||||||
// of values and remote (wrappers over the RPC).
|
// of values and remote (wrappers over the RPC).
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
// Put performs a write operation of UsedSpaceAnnouncement value
|
// Put performs a write operation of container.SizeEstimation value
|
||||||
// and returns any error encountered.
|
// and returns any error encountered.
|
||||||
//
|
//
|
||||||
// All values after the Close call must be flushed to the
|
// All values after the Close call must be flushed to the
|
||||||
|
@ -62,7 +62,7 @@ type Writer interface {
|
||||||
// Close operation.
|
// Close operation.
|
||||||
//
|
//
|
||||||
// Put must not be called after Close.
|
// Put must not be called after Close.
|
||||||
Put(container.UsedSpaceAnnouncement) error
|
Put(container.SizeEstimation) error
|
||||||
|
|
||||||
// Close exits with method-providing Writer.
|
// Close exits with method-providing Writer.
|
||||||
//
|
//
|
||||||
|
@ -75,7 +75,7 @@ type Writer interface {
|
||||||
|
|
||||||
// WriterProvider is a group of methods provided
|
// WriterProvider is a group of methods provided
|
||||||
// by entity which generates keepers of
|
// by entity which generates keepers of
|
||||||
// UsedSpaceAnnouncement values.
|
// container.SizeEstimation values.
|
||||||
type WriterProvider interface {
|
type WriterProvider interface {
|
||||||
// InitWriter should return an initialized Writer.
|
// InitWriter should return an initialized Writer.
|
||||||
//
|
//
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func usedSpaceFilterEpochEQ(epoch uint64) UsedSpaceFilter {
|
func usedSpaceFilterEpochEQ(epoch uint64) UsedSpaceFilter {
|
||||||
return func(a container.UsedSpaceAnnouncement) bool {
|
return func(a container.SizeEstimation) bool {
|
||||||
return a.Epoch() == epoch
|
return a.Epoch() == epoch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package loadroute
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
loadcontroller "github.com/nspcc-dev/neofs-node/pkg/services/container/announcement/load/controller"
|
loadcontroller "github.com/nspcc-dev/neofs-node/pkg/services/container/announcement/load/controller"
|
||||||
|
@ -71,7 +70,7 @@ type routeKey struct {
|
||||||
type valuesRoute struct {
|
type valuesRoute struct {
|
||||||
route []ServerInfo
|
route []ServerInfo
|
||||||
|
|
||||||
values []container.UsedSpaceAnnouncement
|
values []container.SizeEstimation
|
||||||
}
|
}
|
||||||
|
|
||||||
type loadWriter struct {
|
type loadWriter struct {
|
||||||
|
@ -85,18 +84,13 @@ type loadWriter struct {
|
||||||
mServers map[string]loadcontroller.Writer
|
mServers map[string]loadcontroller.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *loadWriter) Put(a container.UsedSpaceAnnouncement) error {
|
func (w *loadWriter) Put(a container.SizeEstimation) error {
|
||||||
cnr, ok := a.ContainerID()
|
|
||||||
if !ok {
|
|
||||||
return errors.New("missing container in load announcement")
|
|
||||||
}
|
|
||||||
|
|
||||||
w.routeMtx.Lock()
|
w.routeMtx.Lock()
|
||||||
defer w.routeMtx.Unlock()
|
defer w.routeMtx.Unlock()
|
||||||
|
|
||||||
key := routeKey{
|
key := routeKey{
|
||||||
epoch: a.Epoch(),
|
epoch: a.Epoch(),
|
||||||
cid: cnr.EncodeToString(),
|
cid: a.Container().EncodeToString(),
|
||||||
}
|
}
|
||||||
|
|
||||||
routeValues, ok := w.mRoute[key]
|
routeValues, ok := w.mRoute[key]
|
||||||
|
@ -110,7 +104,7 @@ func (w *loadWriter) Put(a container.UsedSpaceAnnouncement) error {
|
||||||
|
|
||||||
routeValues = &valuesRoute{
|
routeValues = &valuesRoute{
|
||||||
route: route,
|
route: route,
|
||||||
values: []container.UsedSpaceAnnouncement{a},
|
values: []container.SizeEstimation{a},
|
||||||
}
|
}
|
||||||
|
|
||||||
w.mRoute[key] = routeValues
|
w.mRoute[key] = routeValues
|
||||||
|
|
|
@ -33,7 +33,7 @@ type Builder interface {
|
||||||
// in that list (means that point is the last point in one of the route groups),
|
// in that list (means that point is the last point in one of the route groups),
|
||||||
// returned route must contain nil point that should be interpreted as signal to,
|
// returned route must contain nil point that should be interpreted as signal to,
|
||||||
// among sending to other route points, save the announcement in that point.
|
// among sending to other route points, save the announcement in that point.
|
||||||
NextStage(a container.UsedSpaceAnnouncement, passed []ServerInfo) ([]ServerInfo, error)
|
NextStage(a container.SizeEstimation, passed []ServerInfo) ([]ServerInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteWriterProvider describes the component
|
// RemoteWriterProvider describes the component
|
||||||
|
|
|
@ -2,7 +2,6 @@ package placementrouter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
netmapcore "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
|
@ -16,15 +15,12 @@ import (
|
||||||
// If passed route has more than one point, then endpoint of the route is reached.
|
// If passed route has more than one point, then endpoint of the route is reached.
|
||||||
//
|
//
|
||||||
// The traversed route is not checked, it is assumed to be correct.
|
// The traversed route is not checked, it is assumed to be correct.
|
||||||
func (b *Builder) NextStage(a container.UsedSpaceAnnouncement, passed []loadroute.ServerInfo) ([]loadroute.ServerInfo, error) {
|
func (b *Builder) NextStage(a container.SizeEstimation, passed []loadroute.ServerInfo) ([]loadroute.ServerInfo, error) {
|
||||||
if len(passed) > 1 {
|
if len(passed) > 1 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cnr, ok := a.ContainerID()
|
cnr := a.Container()
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("missing container in load announcement")
|
|
||||||
}
|
|
||||||
|
|
||||||
placement, err := b.placementBuilder.BuildPlacement(a.Epoch(), cnr)
|
placement, err := b.placementBuilder.BuildPlacement(a.Epoch(), cnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,7 +12,7 @@ var errWrongRoute = errors.New("wrong route")
|
||||||
// CheckRoute checks if the route is a route correctly constructed by the builder for value a.
|
// CheckRoute checks if the route is a route correctly constructed by the builder for value a.
|
||||||
//
|
//
|
||||||
// Returns nil if route is correct, otherwise an error clarifying the inconsistency.
|
// Returns nil if route is correct, otherwise an error clarifying the inconsistency.
|
||||||
func CheckRoute(builder Builder, a container.UsedSpaceAnnouncement, route []ServerInfo) error {
|
func CheckRoute(builder Builder, a container.SizeEstimation, route []ServerInfo) error {
|
||||||
for i := 1; i < len(route); i++ {
|
for i := 1; i < len(route); i++ {
|
||||||
servers, err := builder.NextStage(a, route[:i])
|
servers, err := builder.NextStage(a, route[:i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package loadstorage
|
package loadstorage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -10,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type usedSpaceEstimations struct {
|
type usedSpaceEstimations struct {
|
||||||
announcement container.UsedSpaceAnnouncement
|
announcement container.SizeEstimation
|
||||||
|
|
||||||
sizes []uint64
|
sizes []uint64
|
||||||
}
|
}
|
||||||
|
@ -22,7 +21,7 @@ type storageKey struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage represents in-memory storage of
|
// Storage represents in-memory storage of
|
||||||
// UsedSpaceAnnouncement values.
|
// container.SizeEstimation values.
|
||||||
//
|
//
|
||||||
// The write operation has the usual behavior - to save
|
// The write operation has the usual behavior - to save
|
||||||
// the next number of used container space for a specific epoch.
|
// the next number of used container space for a specific epoch.
|
||||||
|
@ -63,18 +62,13 @@ func New(_ Prm) *Storage {
|
||||||
// to the list of already saved values.
|
// to the list of already saved values.
|
||||||
//
|
//
|
||||||
// Always returns nil error.
|
// Always returns nil error.
|
||||||
func (s *Storage) Put(a container.UsedSpaceAnnouncement) error {
|
func (s *Storage) Put(a container.SizeEstimation) error {
|
||||||
cnr, ok := a.ContainerID()
|
|
||||||
if !ok {
|
|
||||||
return errors.New("missing container in load announcement")
|
|
||||||
}
|
|
||||||
|
|
||||||
s.mtx.Lock()
|
s.mtx.Lock()
|
||||||
|
|
||||||
{
|
{
|
||||||
key := storageKey{
|
key := storageKey{
|
||||||
epoch: a.Epoch(),
|
epoch: a.Epoch(),
|
||||||
cid: cnr.EncodeToString(),
|
cid: a.Container().EncodeToString(),
|
||||||
}
|
}
|
||||||
|
|
||||||
estimations, ok := s.mItems[key]
|
estimations, ok := s.mItems[key]
|
||||||
|
@ -87,7 +81,7 @@ func (s *Storage) Put(a container.UsedSpaceAnnouncement) error {
|
||||||
s.mItems[key] = estimations
|
s.mItems[key] = estimations
|
||||||
}
|
}
|
||||||
|
|
||||||
estimations.sizes = append(estimations.sizes, a.UsedSpace())
|
estimations.sizes = append(estimations.sizes, a.Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mtx.Unlock()
|
s.mtx.Unlock()
|
||||||
|
@ -110,7 +104,7 @@ func (s *Storage) Iterate(f loadcontroller.UsedSpaceFilter, h loadcontroller.Use
|
||||||
for _, v := range s.mItems {
|
for _, v := range s.mItems {
|
||||||
if f(v.announcement) {
|
if f(v.announcement) {
|
||||||
// calculate estimation based on 90th percentile
|
// calculate estimation based on 90th percentile
|
||||||
v.announcement.SetUsedSpace(finalEstimation(v.sizes))
|
v.announcement.SetValue(finalEstimation(v.sizes))
|
||||||
|
|
||||||
if err = h(v.announcement); err != nil {
|
if err = h(v.announcement); err != nil {
|
||||||
break
|
break
|
||||||
|
|
|
@ -12,8 +12,8 @@ import (
|
||||||
func TestStorage(t *testing.T) {
|
func TestStorage(t *testing.T) {
|
||||||
const epoch uint64 = 13
|
const epoch uint64 = 13
|
||||||
|
|
||||||
a := container.NewAnnouncement()
|
var a container.SizeEstimation
|
||||||
a.SetContainerID(cidtest.ID())
|
a.SetContainer(cidtest.ID())
|
||||||
a.SetEpoch(epoch)
|
a.SetEpoch(epoch)
|
||||||
|
|
||||||
const opinionsNum = 100
|
const opinionsNum = 100
|
||||||
|
@ -24,25 +24,23 @@ func TestStorage(t *testing.T) {
|
||||||
for i := range opinions {
|
for i := range opinions {
|
||||||
opinions[i] = rand.Uint64()
|
opinions[i] = rand.Uint64()
|
||||||
|
|
||||||
a.SetUsedSpace(opinions[i])
|
a.SetValue(opinions[i])
|
||||||
|
|
||||||
require.NoError(t, s.Put(*a))
|
require.NoError(t, s.Put(a))
|
||||||
}
|
}
|
||||||
|
|
||||||
iterCounter := 0
|
iterCounter := 0
|
||||||
|
|
||||||
err := s.Iterate(
|
err := s.Iterate(
|
||||||
func(ai container.UsedSpaceAnnouncement) bool {
|
func(ai container.SizeEstimation) bool {
|
||||||
return ai.Epoch() == epoch
|
return ai.Epoch() == epoch
|
||||||
},
|
},
|
||||||
func(ai container.UsedSpaceAnnouncement) error {
|
func(ai container.SizeEstimation) error {
|
||||||
iterCounter++
|
iterCounter++
|
||||||
|
|
||||||
require.Equal(t, epoch, ai.Epoch())
|
require.Equal(t, epoch, ai.Epoch())
|
||||||
cnr1, _ := a.ContainerID()
|
require.Equal(t, a.Container(), ai.Container())
|
||||||
cnr2, _ := ai.ContainerID()
|
require.Equal(t, finalEstimation(opinions), ai.Value())
|
||||||
require.Equal(t, cnr1, cnr2)
|
|
||||||
require.Equal(t, finalEstimation(opinions), ai.UsedSpace())
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
containercore "github.com/nspcc-dev/neofs-node/pkg/core/container"
|
containercore "github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||||
containerSvc "github.com/nspcc-dev/neofs-node/pkg/services/container"
|
containerSvc "github.com/nspcc-dev/neofs-node/pkg/services/container"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object/acl/eacl"
|
||||||
containerSDK "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"
|
||||||
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/session"
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
@ -58,8 +57,16 @@ func (s *morphExecutor) Put(_ context.Context, tokV2 *sessionV2.Token, body *con
|
||||||
return nil, errors.New("missing signature")
|
return nil, errors.New("missing signature")
|
||||||
}
|
}
|
||||||
|
|
||||||
cnr := containercore.Container{
|
cnrV2 := body.GetContainer()
|
||||||
Value: containerSDK.NewContainerFromV2(body.GetContainer()),
|
if cnrV2 == nil {
|
||||||
|
return nil, errors.New("missing container field")
|
||||||
|
}
|
||||||
|
|
||||||
|
var cnr containercore.Container
|
||||||
|
|
||||||
|
err := cnr.Value.ReadFromV2(*cnrV2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cnr.Signature.ReadFromV2(*sigV2)
|
cnr.Signature.ReadFromV2(*sigV2)
|
||||||
|
@ -158,8 +165,11 @@ func (s *morphExecutor) Get(ctx context.Context, body *container.GetRequestBody)
|
||||||
cnr.Session.WriteToV2(tokV2)
|
cnr.Session.WriteToV2(tokV2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cnrV2 container.Container
|
||||||
|
cnr.Value.WriteToV2(&cnrV2)
|
||||||
|
|
||||||
res := new(container.GetResponseBody)
|
res := new(container.GetResponseBody)
|
||||||
res.SetContainer(cnr.Value.ToV2())
|
res.SetContainer(&cnrV2)
|
||||||
res.SetSignature(sigV2)
|
res.SetSignature(sigV2)
|
||||||
res.SetSessionToken(tokV2)
|
res.SetSessionToken(tokV2)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
containerSvcMorph "github.com/nspcc-dev/neofs-node/pkg/services/container/morph"
|
containerSvcMorph "github.com/nspcc-dev/neofs-node/pkg/services/container/morph"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
|
containertest "github.com/nspcc-dev/neofs-sdk-go/container/test"
|
||||||
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
|
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -54,6 +55,13 @@ func TestInvalidToken(t *testing.T) {
|
||||||
var reqBody container.PutRequestBody
|
var reqBody container.PutRequestBody
|
||||||
reqBody.SetSignature(new(refs.Signature))
|
reqBody.SetSignature(new(refs.Signature))
|
||||||
|
|
||||||
|
cnr := containertest.Container()
|
||||||
|
|
||||||
|
var cnrV2 container.Container
|
||||||
|
cnr.WriteToV2(&cnrV2)
|
||||||
|
|
||||||
|
reqBody.SetContainer(&cnrV2)
|
||||||
|
|
||||||
_, err = e.Put(context.TODO(), tokV2, &reqBody)
|
_, err = e.Put(context.TODO(), tokV2, &reqBody)
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,6 @@ package v2
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"errors"
|
|
||||||
|
|
||||||
core "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
core "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
|
@ -27,12 +26,7 @@ type classifyResult struct {
|
||||||
func (c senderClassifier) classify(
|
func (c senderClassifier) classify(
|
||||||
req MetaWithToken,
|
req MetaWithToken,
|
||||||
idCnr cid.ID,
|
idCnr cid.ID,
|
||||||
cnr *container.Container) (res *classifyResult, err error) {
|
cnr container.Container) (res *classifyResult, err error) {
|
||||||
ownerCnr := cnr.OwnerID()
|
|
||||||
if ownerCnr == nil {
|
|
||||||
return nil, errors.New("missing container owner")
|
|
||||||
}
|
|
||||||
|
|
||||||
ownerID, ownerKey, err := req.RequestOwner()
|
ownerID, ownerKey, err := req.RequestOwner()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -43,7 +37,7 @@ func (c senderClassifier) classify(
|
||||||
// TODO: #767 get owner from neofs.id if present
|
// TODO: #767 get owner from neofs.id if present
|
||||||
|
|
||||||
// if request owner is the same as container owner, return RoleUser
|
// if request owner is the same as container owner, return RoleUser
|
||||||
if ownerID.Equals(*ownerCnr) {
|
if ownerID.Equals(cnr.Owner()) {
|
||||||
return &classifyResult{
|
return &classifyResult{
|
||||||
role: acl.RoleOwner,
|
role: acl.RoleOwner,
|
||||||
key: ownerKeyInBytes,
|
key: ownerKeyInBytes,
|
||||||
|
@ -104,7 +98,7 @@ func (c senderClassifier) isInnerRingKey(owner []byte) (bool, error) {
|
||||||
|
|
||||||
func (c senderClassifier) isContainerKey(
|
func (c senderClassifier) isContainerKey(
|
||||||
owner, idCnr []byte,
|
owner, idCnr []byte,
|
||||||
cnr *container.Container) (bool, error) {
|
cnr container.Container) (bool, error) {
|
||||||
nm, err := core.GetLatestNetworkMap(c.netmap) // first check current netmap
|
nm, err := core.GetLatestNetworkMap(c.netmap) // first check current netmap
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -130,13 +124,8 @@ 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) {
|
||||||
policy := cnr.PlacementPolicy()
|
cnrVectors, err := nm.ContainerNodes(cnr.PlacementPolicy(), idCnr)
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -506,8 +506,6 @@ func (b Service) findRequestInfo(req MetaWithToken, idCnr cid.ID, op acl.Op) (in
|
||||||
cnr, err := b.containers.Get(idCnr) // fetch actual container
|
cnr, err := b.containers.Get(idCnr) // fetch actual container
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return info, err
|
return info, err
|
||||||
} else if cnr.Value.OwnerID() == nil {
|
|
||||||
return info, errors.New("missing owner in container descriptor")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.token != nil {
|
if req.token != nil {
|
||||||
|
@ -534,7 +532,7 @@ func (b Service) findRequestInfo(req MetaWithToken, idCnr cid.ID, op acl.Op) (in
|
||||||
info.basicACL = cnr.Value.BasicACL()
|
info.basicACL = cnr.Value.BasicACL()
|
||||||
info.requestRole = res.role
|
info.requestRole = res.role
|
||||||
info.operation = op
|
info.operation = op
|
||||||
info.cnrOwner = *cnr.Value.OwnerID()
|
info.cnrOwner = cnr.Value.Owner()
|
||||||
info.idCnr = idCnr
|
info.idCnr = idCnr
|
||||||
|
|
||||||
// it is assumed that at the moment the key will be valid,
|
// it is assumed that at the moment the key will be valid,
|
||||||
|
|
|
@ -35,7 +35,7 @@ type testStorage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type testTraverserGenerator struct {
|
type testTraverserGenerator struct {
|
||||||
c *container.Container
|
c container.Container
|
||||||
b map[uint64]placement.Builder
|
b map[uint64]placement.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ func newTestStorage() *testStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *testTraverserGenerator) GenerateTraverser(cnr cid.ID, obj *oid.ID, e uint64) (*placement.Traverser, error) {
|
func (g *testTraverserGenerator) GenerateTraverser(cnr cid.ID, obj *oid.ID, e uint64) (*placement.Traverser, error) {
|
||||||
opts := make([]placement.Option, 3, 4)
|
opts := make([]placement.Option, 0, 4)
|
||||||
opts = append(opts,
|
opts = append(opts,
|
||||||
placement.ForContainer(g.c),
|
placement.ForContainer(g.c),
|
||||||
placement.UseBuilder(g.b[e]),
|
placement.UseBuilder(g.b[e]),
|
||||||
|
@ -466,9 +466,11 @@ 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()
|
||||||
|
|
||||||
pp := netmaptest.PlacementPolicy()
|
var cnr container.Container
|
||||||
cnr := container.New(container.WithPolicy(&pp))
|
cnr.SetPlacementPolicy(netmaptest.PlacementPolicy())
|
||||||
idCnr := container.CalculateID(cnr)
|
|
||||||
|
var idCnr cid.ID
|
||||||
|
container.CalculateID(&idCnr, cnr)
|
||||||
|
|
||||||
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
||||||
svc := &Service{cfg: new(cfg)}
|
svc := &Service{cfg: new(cfg)}
|
||||||
|
@ -1119,9 +1121,11 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
func TestGetFromPastEpoch(t *testing.T) {
|
func TestGetFromPastEpoch(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
pp := netmaptest.PlacementPolicy()
|
var cnr container.Container
|
||||||
cnr := container.New(container.WithPolicy(&pp))
|
cnr.SetPlacementPolicy(netmaptest.PlacementPolicy())
|
||||||
idCnr := container.CalculateID(cnr)
|
|
||||||
|
var idCnr cid.ID
|
||||||
|
container.CalculateID(&idCnr, cnr)
|
||||||
|
|
||||||
addr := oidtest.Address()
|
addr := oidtest.Address()
|
||||||
addr.SetContainer(idCnr)
|
addr.SetContainer(idCnr)
|
||||||
|
|
|
@ -33,7 +33,7 @@ type testStorage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type testTraverserGenerator struct {
|
type testTraverserGenerator struct {
|
||||||
c *container.Container
|
c container.Container
|
||||||
b map[uint64]placement.Builder
|
b map[uint64]placement.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,8 +241,11 @@ func TestGetRemoteSmall(t *testing.T) {
|
||||||
var pp netmap.PlacementPolicy
|
var pp netmap.PlacementPolicy
|
||||||
pp.AddReplicas(rs...)
|
pp.AddReplicas(rs...)
|
||||||
|
|
||||||
cnr := container.New(container.WithPolicy(&pp))
|
var cnr container.Container
|
||||||
id := container.CalculateID(cnr)
|
cnr.SetPlacementPolicy(pp)
|
||||||
|
|
||||||
|
var id cid.ID
|
||||||
|
container.CalculateID(&id, cnr)
|
||||||
|
|
||||||
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
|
||||||
svc := &Service{cfg: new(cfg)}
|
svc := &Service{cfg: new(cfg)}
|
||||||
|
@ -327,8 +330,11 @@ func TestGetFromPastEpoch(t *testing.T) {
|
||||||
var pp netmap.PlacementPolicy
|
var pp netmap.PlacementPolicy
|
||||||
pp.AddReplicas(rs...)
|
pp.AddReplicas(rs...)
|
||||||
|
|
||||||
cnr := container.New(container.WithPolicy(&pp))
|
var cnr container.Container
|
||||||
idCnr := container.CalculateID(cnr)
|
cnr.SetPlacementPolicy(pp)
|
||||||
|
|
||||||
|
var idCnr cid.ID
|
||||||
|
container.CalculateID(&idCnr, cnr)
|
||||||
|
|
||||||
var addr oid.Address
|
var addr oid.Address
|
||||||
addr.SetContainer(idCnr)
|
addr.SetContainer(idCnr)
|
||||||
|
|
|
@ -45,7 +45,8 @@ type cfg struct {
|
||||||
|
|
||||||
obj *oid.ID
|
obj *oid.ID
|
||||||
|
|
||||||
policy *netmap.PlacementPolicy
|
policySet bool
|
||||||
|
policy netmap.PlacementPolicy
|
||||||
|
|
||||||
builder Builder
|
builder Builder
|
||||||
}
|
}
|
||||||
|
@ -74,11 +75,11 @@ func NewTraverser(opts ...Option) (*Traverser, error) {
|
||||||
|
|
||||||
if cfg.builder == nil {
|
if cfg.builder == nil {
|
||||||
return nil, fmt.Errorf("%s: %w", invalidOptsMsg, errNilBuilder)
|
return nil, fmt.Errorf("%s: %w", invalidOptsMsg, errNilBuilder)
|
||||||
} else if cfg.policy == nil {
|
} else if !cfg.policySet {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -219,10 +220,11 @@ func UseBuilder(b Builder) Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForContainer is a traversal container setting option.
|
// ForContainer is a traversal container setting option.
|
||||||
func ForContainer(cnr *container.Container) Option {
|
func ForContainer(cnr container.Container) Option {
|
||||||
return func(c *cfg) {
|
return func(c *cfg) {
|
||||||
c.policy = cnr.PlacementPolicy()
|
c.policy = cnr.PlacementPolicy()
|
||||||
c.cnr = container.CalculateID(cnr)
|
c.policySet = true
|
||||||
|
container.CalculateID(&c.cnr, cnr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ func copyVectors(v [][]netmap.NodeInfo) [][]netmap.NodeInfo {
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPlacement(t *testing.T, ss, rs []int) ([][]netmap.NodeInfo, *container.Container) {
|
func testPlacement(t *testing.T, ss, rs []int) ([][]netmap.NodeInfo, container.Container) {
|
||||||
nodes := make([][]netmap.NodeInfo, 0, len(rs))
|
nodes := make([][]netmap.NodeInfo, 0, len(rs))
|
||||||
replicas := make([]netmap.ReplicaDescriptor, 0, len(rs))
|
replicas := make([]netmap.ReplicaDescriptor, 0, len(rs))
|
||||||
num := uint32(0)
|
num := uint32(0)
|
||||||
|
@ -61,10 +61,13 @@ func testPlacement(t *testing.T, ss, rs []int) ([][]netmap.NodeInfo, *container.
|
||||||
replicas = append(replicas, rd)
|
replicas = append(replicas, rd)
|
||||||
}
|
}
|
||||||
|
|
||||||
policy := new(netmap.PlacementPolicy)
|
var policy netmap.PlacementPolicy
|
||||||
policy.AddReplicas(replicas...)
|
policy.AddReplicas(replicas...)
|
||||||
|
|
||||||
return nodes, container.New(container.WithPolicy(policy))
|
var cnr container.Container
|
||||||
|
cnr.SetPlacementPolicy(policy)
|
||||||
|
|
||||||
|
return nodes, cnr
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertSameAddress(t *testing.T, ni netmap.NodeInfo, addr network.AddressGroup) {
|
func assertSameAddress(t *testing.T, ni netmap.NodeInfo, addr network.AddressGroup) {
|
||||||
|
|
|
@ -45,17 +45,9 @@ func (p *Policer) processObject(ctx context.Context, addr oid.Address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
policy := cnr.Value.PlacementPolicy()
|
policy := cnr.Value.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()),
|
||||||
|
|
Loading…
Reference in a new issue