From 0e4c2001d49d49eb96b331e8dc9c99db0cc2d682 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Tue, 25 Feb 2025 09:57:16 +0300 Subject: [PATCH] ir/container: Check quantitative policy limits of created containers Follow https://github.com/nspcc-dev/neofs-api/issues/307. Refs #3075. Signed-off-by: Leonard Lyubich --- .../processors/container/process_container.go | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/pkg/innerring/processors/container/process_container.go b/pkg/innerring/processors/container/process_container.go index 77d81ab74a..b2296d8f80 100644 --- a/pkg/innerring/processors/container/process_container.go +++ b/pkg/innerring/processors/container/process_container.go @@ -1,7 +1,9 @@ package container import ( + "errors" "fmt" + "slices" "strings" "github.com/nspcc-dev/neo-go/pkg/network/payload" @@ -10,6 +12,7 @@ import ( containerEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/container" containerSDK "github.com/nspcc-dev/neofs-sdk-go/container" 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/session" "go.uber.org/zap" ) @@ -106,6 +109,10 @@ func (cp *Processor) checkPutContainer(ctx *putContainerContext) error { return fmt.Errorf("auth container creation: %w", err) } + if err = verifyStoragePolicy(ctx.cnr.PlacementPolicy()); err != nil { + return fmt.Errorf("invalid storage policy: %w", err) + } + // check homomorphic hashing setting err = checkHomomorphicHashing(cp.netState, ctx.cnr) if err != nil { @@ -265,3 +272,51 @@ func checkHomomorphicHashing(ns NetworkState, cnr containerSDK.Container) error return nil } + +const ( + maxObjectReplicasPerSet = 8 + maxContainerNodesInSet = 64 + maxContainerNodeSets = 256 + maxContainerNodes = 512 +) + +const defaultBackupFactor = 3 + +var errInvalidNodeSetDesc = errors.New("invalid node set descriptor") + +func verifyStoragePolicy(policy netmap.PlacementPolicy) error { + rs := policy.Replicas() + if len(rs) > maxContainerNodeSets { + return fmt.Errorf("more than %d node sets", maxContainerNodeSets) + } + ss := policy.Selectors() + bf := policy.ContainerBackupFactor() + if bf == 0 { + bf = defaultBackupFactor + } + var cnrNodeCount uint32 + for i := range rs { + rNum := rs[i].NumberOfObjects() + if rNum > maxObjectReplicasPerSet { + return fmt.Errorf("%w #%d: more than %d object replicas", errInvalidNodeSetDesc, i, maxObjectReplicasPerSet) + } + var sNum uint32 + if sName := rs[i].SelectorName(); sName != "" { + si := slices.IndexFunc(ss, func(s netmap.Selector) bool { return s.Name() == sName }) + if si < 0 { + return fmt.Errorf("%w #%d: missing selector %q", errInvalidNodeSetDesc, i, sName) + } + sNum = ss[si].NumberOfNodes() + } else { + sNum = rNum + } + nodesInSet := bf * sNum + if nodesInSet > maxContainerNodesInSet { + return fmt.Errorf("%w #%d: more than %d nodes", errInvalidNodeSetDesc, i, maxContainerNodesInSet) + } + if cnrNodeCount += nodesInSet; cnrNodeCount > maxContainerNodes { + return fmt.Errorf("more than %d nodes in total", maxContainerNodes) + } + } + return nil +}