Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Changelog for NeoFS Node
- `policer.boost_multiplier` SN config option (#3855)
- `neofs-lens storage flush-write-caches` command (#3872)
- Reload gRPC SN config with SIGHUP (#3874)
- Support for creation of containers with initial placement policy (#3830)

### Fixed
- Resending the header after chunks have already been sent in object service `Get` handler (#3833)
Expand All @@ -30,6 +31,7 @@ Changelog for NeoFS Node
- Optimized local HEAD request execution (#3783)
- Unpaid container's data is deleted now (#3691)
- Policer iterates engine-level object list now instead of shard-level (#3862)
- SN now ignores `copies_number` field of `object.PutRequest.Body.Init` message (#3830)

### Removed
- `node.persistent_sessions.path` config option from SN config (#3846)
Expand All @@ -39,7 +41,7 @@ Changelog for NeoFS Node
- Metabase v5 to v6 and v6 to v7 migrations (#3864)

### Updated
- `github.com/nspcc-dev/neofs-sdk-go` module to `v1.0.0-rc.17.0.20260224112648-e6342b6bf094` (#3785, #3817, #3808)
- `github.com/nspcc-dev/neofs-sdk-go` module to `v1.0.0-rc.17.0.20260226163827-b703a4861e06` (#3785, #3817, #3808, #3830)
- Go 1.25+ is required to build now (#3525)
- `github.com/klauspost/compress` dependency from v1.18.0 to v1.18.4 (#3850)
- `github.com/klauspost/reedsolomon` dependency from v1.12.5 to v1.13.2 (#3850)
Expand All @@ -65,6 +67,9 @@ Storage nodes no longer automatically migrate metabases from version 5

Storage nodes clean up objects that belong to unpdaid containers.

`copies_number` parameter of object PUT request no longer has an effect. Use
`max_replicas` setting of container's initial placement policy instead.

## [0.51.1] - 2026-02-18

### Added
Expand Down
37 changes: 36 additions & 1 deletion cmd/neofs-cli/modules/container/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/container"
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -113,11 +114,45 @@ func prettyPrintContainer(cmd *cobra.Command, id cid.ID, cnr container.Container
cmd.Printf("\t%s=%s\n", key, val)
}

policy := cnr.PlacementPolicy()
repRules := policy.Replicas()

cmd.Println("placement policy:")
if err := cnr.PlacementPolicy().WriteStringTo((*stringWriter)(cmd)); err != nil {
// https://github.com/nspcc-dev/neofs-sdk-go/issues/789
var policyCp netmap.PlacementPolicy
policyCp.SetReplicas(repRules)
policyCp.SetSelectors(policy.Selectors())
policyCp.SetFilters(policy.Filters())
policyCp.SetECRules(policy.ECRules())
policyCp.SetContainerBackupFactor(policy.ContainerBackupFactor())
if err := policyCp.WriteStringTo((*stringWriter)(cmd)); err != nil {
return fmt.Errorf("write policy: %w", err)
}
cmd.Println()

initialPolicy := policy.Initial()
if initialPolicy == nil {
return nil
}

cmd.Printf("INITIAL")
if repLimits := initialPolicy.ReplicaLimits(); len(repLimits) != 0 {
for i := range repLimits {
if i < len(repRules) {
cmd.Printf(" REP %d", repLimits[i])
} else {
cmd.Printf(" EC %d", repLimits[i])
}
}
}
if maxReplicas := initialPolicy.MaxReplicas(); maxReplicas != 0 {
cmd.Printf(" MAX %d", maxReplicas)
}
if initialPolicy.PreferLocal() {
cmd.Print(" LOCAL")
}
cmd.Println()

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/nspcc-dev/neo-go v0.117.1-0.20260226134506-d9d26157b697
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea
github.com/nspcc-dev/neofs-contract v0.26.1
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.17.0.20260224112648-e6342b6bf094
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.17.0.20260226163827-b703a4861e06
github.com/nspcc-dev/tzhash v1.8.4
github.com/panjf2000/ants/v2 v2.11.5
github.com/prometheus/client_golang v1.23.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea h1:mK
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea/go.mod h1:YzhD4EZmC9Z/PNyd7ysC7WXgIgURc9uCG1UWDeV027Y=
github.com/nspcc-dev/neofs-contract v0.26.1 h1:7Ii7Q4L3au408LOsIWKiSgfnT1g8G9jo3W7381d41T8=
github.com/nspcc-dev/neofs-contract v0.26.1/go.mod h1:pevVF9OWdEN5bweKxOu6ryZv9muCEtS1ppzYM4RfBIo=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.17.0.20260224112648-e6342b6bf094 h1:NosmYG45BKXtW5aP+7nT0Q+ZI7hjyYRdSFozy2tetmQ=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.17.0.20260224112648-e6342b6bf094/go.mod h1:y2vNz9DVTqBkR7ctYb6taLnabWTtG7xtCHlGofEpKOM=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.17.0.20260226163827-b703a4861e06 h1:lhVbjycfOI9sEvMQEvBPXjQvLGkz9QyRYSN2f4OQb+E=
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.17.0.20260226163827-b703a4861e06/go.mod h1:y2vNz9DVTqBkR7ctYb6taLnabWTtG7xtCHlGofEpKOM=
github.com/nspcc-dev/rfc6979 v0.2.4 h1:NBgsdCjhLpEPJZqmC9rciMZDcSY297po2smeaRjw57k=
github.com/nspcc-dev/rfc6979 v0.2.4/go.mod h1:86ylDw6Kss+P6v4QAJqo1Sp3mC0/Zr9G97xSjQ9TuFg=
github.com/nspcc-dev/tzhash v1.8.4 h1:lvuPGWsqEo9dVEvo/kdNLKv/Cy0yxRs9z5hJp8VcBuo=
Expand Down
11 changes: 9 additions & 2 deletions pkg/innerring/processors/container/process_container.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,18 @@ var allowedSystemAttributes = map[string]struct{}{
}

func (cp *Processor) checkPutContainer(cnr containerSDK.Container, cnrBytes, sessionToken, invocScript, verifScript []byte, domainName, domainZone string) error {
var metaEnabled bool
for k := range cnr.Attributes() {
if strings.HasPrefix(k, sysAttrPrefix) {
if _, ok := allowedSystemAttributes[k]; !ok {
return fmt.Errorf("system attribute %s is not allowed", k)
}

if k == sysAttrChainMeta && !cp.metaEnabled {
return errors.New("chain meta data attribute is not allowed")
if k == sysAttrChainMeta {
if !cp.metaEnabled {
return errors.New("chain meta data attribute is not allowed")
}
metaEnabled = true
}
}
}
Expand All @@ -115,6 +119,9 @@ func (cp *Processor) checkPutContainer(cnr containerSDK.Container, cnrBytes, ses
if len(ecRules) > 0 && cnr.PlacementPolicy().NumberOfReplicas() > 0 {
return errors.New("REP+EC rules are not supported yet")
}
if metaEnabled && cnr.PlacementPolicy().Initial() != nil {
return errors.New("initial placement policies with consistent metadata are not supported yet")
}

err := cp.verifySignature(signatureVerificationData{
ownerContainer: cnr.Owner(),
Expand Down
37 changes: 0 additions & 37 deletions pkg/services/object/put/distibuted_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,43 +148,6 @@ func TestIterateNodesForObject(t *testing.T) {
require.ElementsMatch(t, expNetAddrs, []string{node.info.AddressGroup()[0].URIAddr(), node.info.AddressGroup()[1].URIAddr()})
}

t.Run("linear num of replicas", func(t *testing.T) {
// nodes: [A B C] [D B E] [F G]
// policy: [2 1 2]
// B fails, all others succeed
// linear num: 4
//
// expected order of candidates: [A B C D E]
objID := oidtest.ID()
cnrNodes := allocNodes([]uint{3, 3, 2})
cnrNodes[1][1].SetPublicKey(cnrNodes[0][1].PublicKey())
iter := placementIterator{
log: zaptest.NewLogger(t),
neoFSNet: new(testNetwork),
remotePool: new(testWorkerPool),
linearReplNum: 4,
}
var handlerMtx sync.Mutex
var handlerCalls [][]byte
err := iter.iterateNodesForObject(objID, []uint{2, 1, 2}, cnrNodes, false, func(node nodeDesc) error {
handlerMtx.Lock()
handlerCalls = append(handlerCalls, node.info.PublicKey())
handlerMtx.Unlock()
if bytes.Equal(node.info.PublicKey(), cnrNodes[0][1].PublicKey()) {
return errors.New("any node error")
}
return nil
})
require.NoError(t, err)
require.Len(t, handlerCalls, 5)
require.ElementsMatch(t, [][]byte{
cnrNodes[0][0].PublicKey(),
cnrNodes[0][1].PublicKey(),
cnrNodes[0][2].PublicKey(),
cnrNodes[1][0].PublicKey(),
cnrNodes[1][2].PublicKey(),
}, handlerCalls)
})
t.Run("broadcast", func(t *testing.T) {
// nodes: [A B] [C D B] [E F]
// policy: [1 1 1]
Expand Down
Loading
Loading