Compare commits
15 commits
master
...
support/v0
Author | SHA1 | Date | |
---|---|---|---|
74e11b3cf3 | |||
f527556735 | |||
23b426ec4a | |||
7e3f2fca47 | |||
25ed595354 | |||
fb2f40aea1 | |||
15b4288d80 | |||
6ea8f2b23c | |||
47f12f8440 | |||
edc1824c23 | |||
cf48dfd55e | |||
274ac61236 | |||
892542d6e3 | |||
af3d6368b0 | |||
36fe470956 |
27 changed files with 229 additions and 99 deletions
|
@ -51,7 +51,7 @@ var listContainersCmd = &cobra.Command{
|
||||||
|
|
||||||
var prm internalclient.ListContainersPrm
|
var prm internalclient.ListContainersPrm
|
||||||
prm.SetClient(cli)
|
prm.SetClient(cli)
|
||||||
prm.Account = idUser
|
prm.OwnerID = idUser
|
||||||
|
|
||||||
res, err := internalclient.ListContainers(cmd.Context(), prm)
|
res, err := internalclient.ListContainers(cmd.Context(), prm)
|
||||||
commonCmd.ExitOnErr(cmd, "rpc error: %w", err)
|
commonCmd.ExitOnErr(cmd, "rpc error: %w", err)
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"cmp"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
||||||
|
@ -507,7 +504,6 @@ func isObjectStoredOnNode(ctx context.Context, cmd *cobra.Command, cnrID cid.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
func printPlacement(cmd *cobra.Command, objID oid.ID, objects []phyObject, result *objectNodesResult) {
|
func printPlacement(cmd *cobra.Command, objID oid.ID, objects []phyObject, result *objectNodesResult) {
|
||||||
normilizeObjectNodesResult(objects, result)
|
|
||||||
if json, _ := cmd.Flags().GetBool(commonflags.JSON); json {
|
if json, _ := cmd.Flags().GetBool(commonflags.JSON); json {
|
||||||
printObjectNodesAsJSON(cmd, objID, objects, result)
|
printObjectNodesAsJSON(cmd, objID, objects, result)
|
||||||
} else {
|
} else {
|
||||||
|
@ -515,34 +511,6 @@ func printPlacement(cmd *cobra.Command, objID oid.ID, objects []phyObject, resul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func normilizeObjectNodesResult(objects []phyObject, result *objectNodesResult) {
|
|
||||||
slices.SortFunc(objects, func(lhs, rhs phyObject) int {
|
|
||||||
if lhs.ecHeader == nil && rhs.ecHeader == nil {
|
|
||||||
return bytes.Compare(lhs.objectID[:], rhs.objectID[:])
|
|
||||||
}
|
|
||||||
if lhs.ecHeader == nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if rhs.ecHeader == nil {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
if lhs.ecHeader.parent == rhs.ecHeader.parent {
|
|
||||||
return cmp.Compare(lhs.ecHeader.index, rhs.ecHeader.index)
|
|
||||||
}
|
|
||||||
return bytes.Compare(lhs.ecHeader.parent[:], rhs.ecHeader.parent[:])
|
|
||||||
})
|
|
||||||
for _, obj := range objects {
|
|
||||||
op := result.placements[obj.objectID]
|
|
||||||
slices.SortFunc(op.confirmedNodes, func(lhs, rhs netmapSDK.NodeInfo) int {
|
|
||||||
return bytes.Compare(lhs.PublicKey(), rhs.PublicKey())
|
|
||||||
})
|
|
||||||
slices.SortFunc(op.requiredNodes, func(lhs, rhs netmapSDK.NodeInfo) int {
|
|
||||||
return bytes.Compare(lhs.PublicKey(), rhs.PublicKey())
|
|
||||||
})
|
|
||||||
result.placements[obj.objectID] = op
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func printObjectNodesAsText(cmd *cobra.Command, objID oid.ID, objects []phyObject, result *objectNodesResult) {
|
func printObjectNodesAsText(cmd *cobra.Command, objID oid.ID, objects []phyObject, result *objectNodesResult) {
|
||||||
fmt.Fprintf(cmd.OutOrStdout(), "Object %s stores payload in %d data objects:\n", objID.EncodeToString(), len(objects))
|
fmt.Fprintf(cmd.OutOrStdout(), "Object %s stores payload in %d data objects:\n", objID.EncodeToString(), len(objects))
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,10 @@ func IterateShards(c *config.Config, required bool, f func(*shardconfig.Config)
|
||||||
c.Sub(si),
|
c.Sub(si),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if sc.Mode() == mode.Disabled {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Path for the blobstor can't be present in the default section, because different shards
|
// Path for the blobstor can't be present in the default section, because different shards
|
||||||
// must have different paths, so if it is missing, the shard is not here.
|
// must have different paths, so if it is missing, the shard is not here.
|
||||||
// At the same time checking for "blobstor" section doesn't work proper
|
// At the same time checking for "blobstor" section doesn't work proper
|
||||||
|
@ -50,10 +54,6 @@ func IterateShards(c *config.Config, required bool, f func(*shardconfig.Config)
|
||||||
}
|
}
|
||||||
(*config.Config)(sc).SetDefault(def)
|
(*config.Config)(sc).SetDefault(def)
|
||||||
|
|
||||||
if sc.Mode() == mode.Disabled {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := f(sc); err != nil {
|
if err := f(sc); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,22 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestIterateShards(t *testing.T) {
|
||||||
|
fileConfigTest := func(c *config.Config) {
|
||||||
|
var res []string
|
||||||
|
require.NoError(t,
|
||||||
|
engineconfig.IterateShards(c, false, func(sc *shardconfig.Config) error {
|
||||||
|
res = append(res, sc.Metabase().Path())
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
require.Equal(t, []string{"abc", "xyz"}, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
const cfgDir = "./testdata/shards"
|
||||||
|
configtest.ForEachFileType(cfgDir, fileConfigTest)
|
||||||
|
configtest.ForEnvFileType(t, cfgDir, fileConfigTest)
|
||||||
|
}
|
||||||
|
|
||||||
func TestEngineSection(t *testing.T) {
|
func TestEngineSection(t *testing.T) {
|
||||||
t.Run("defaults", func(t *testing.T) {
|
t.Run("defaults", func(t *testing.T) {
|
||||||
empty := configtest.EmptyConfig()
|
empty := configtest.EmptyConfig()
|
||||||
|
|
3
cmd/frostfs-node/config/engine/testdata/shards.env
vendored
Normal file
3
cmd/frostfs-node/config/engine/testdata/shards.env
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
FROSTFS_STORAGE_SHARD_0_METABASE_PATH=abc
|
||||||
|
FROSTFS_STORAGE_SHARD_1_MODE=disabled
|
||||||
|
FROSTFS_STORAGE_SHARD_2_METABASE_PATH=xyz
|
13
cmd/frostfs-node/config/engine/testdata/shards.json
vendored
Normal file
13
cmd/frostfs-node/config/engine/testdata/shards.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"storage.shard": {
|
||||||
|
"0": {
|
||||||
|
"metabase.path": "abc"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"mode": "disabled"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"metabase.path": "xyz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
cmd/frostfs-node/config/engine/testdata/shards.yaml
vendored
Normal file
7
cmd/frostfs-node/config/engine/testdata/shards.yaml
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
storage.shard:
|
||||||
|
0:
|
||||||
|
metabase.path: abc
|
||||||
|
1:
|
||||||
|
mode: disabled
|
||||||
|
2:
|
||||||
|
metabase.path: xyz
|
32
go.mod
32
go.mod
|
@ -8,7 +8,7 @@ require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0
|
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-locode-db v0.4.1-0.20240710074952-65761deb5c0d
|
git.frostfs.info/TrueCloudLab/frostfs-locode-db v0.4.1-0.20240710074952-65761deb5c0d
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20241107121119-cb813e27a823
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20241226115718-82e48c8a634d
|
||||||
git.frostfs.info/TrueCloudLab/hrw v1.2.1
|
git.frostfs.info/TrueCloudLab/hrw v1.2.1
|
||||||
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972
|
git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972
|
||||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240814080254-96225afacb88
|
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240814080254-96225afacb88
|
||||||
|
@ -27,7 +27,7 @@ require (
|
||||||
github.com/klauspost/compress v1.17.4
|
github.com/klauspost/compress v1.17.4
|
||||||
github.com/mailru/easyjson v0.7.7
|
github.com/mailru/easyjson v0.7.7
|
||||||
github.com/mr-tron/base58 v1.2.0
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/multiformats/go-multiaddr v0.12.1
|
github.com/multiformats/go-multiaddr v0.14.0
|
||||||
github.com/nspcc-dev/neo-go v0.106.3
|
github.com/nspcc-dev/neo-go v0.106.3
|
||||||
github.com/olekukonko/tablewriter v0.0.5
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
github.com/panjf2000/ants/v2 v2.9.0
|
github.com/panjf2000/ants/v2 v2.9.0
|
||||||
|
@ -40,15 +40,15 @@ require (
|
||||||
github.com/ssgreg/journald v1.0.0
|
github.com/ssgreg/journald v1.0.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
go.etcd.io/bbolt v1.3.10
|
go.etcd.io/bbolt v1.3.10
|
||||||
go.opentelemetry.io/otel v1.28.0
|
go.opentelemetry.io/otel v1.31.0
|
||||||
go.opentelemetry.io/otel/trace v1.28.0
|
go.opentelemetry.io/otel/trace v1.31.0
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.10.0
|
||||||
golang.org/x/sys v0.22.0
|
golang.org/x/sys v0.28.0
|
||||||
golang.org/x/term v0.21.0
|
golang.org/x/term v0.27.0
|
||||||
google.golang.org/grpc v1.66.2
|
google.golang.org/grpc v1.69.2
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.36.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -119,15 +119,15 @@ require (
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 // indirect
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
go.opentelemetry.io/otel/metric v1.31.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.31.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/crypto v0.24.0 // indirect
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
golang.org/x/net v0.26.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.21.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
lukechampine.com/blake3 v1.2.1 // indirect
|
lukechampine.com/blake3 v1.2.1 // indirect
|
||||||
rsc.io/tmplfunc v0.0.3 // indirect
|
rsc.io/tmplfunc v0.0.3 // indirect
|
||||||
|
|
BIN
go.sum
BIN
go.sum
Binary file not shown.
|
@ -42,7 +42,7 @@ func benchmarkExists(b *testing.B, shardNum int) {
|
||||||
for range b.N {
|
for range b.N {
|
||||||
var shPrm shard.ExistsPrm
|
var shPrm shard.ExistsPrm
|
||||||
shPrm.Address = addr
|
shPrm.Address = addr
|
||||||
shPrm.ParentAddress = oid.Address{}
|
shPrm.ECParentAddress = oid.Address{}
|
||||||
ok, _, err := e.exists(context.Background(), shPrm)
|
ok, _, err := e.exists(context.Background(), shPrm)
|
||||||
if err != nil || ok {
|
if err != nil || ok {
|
||||||
b.Fatalf("%t %v", ok, err)
|
b.Fatalf("%t %v", ok, err)
|
||||||
|
|
|
@ -7,8 +7,11 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
|
||||||
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
||||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||||
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||||
|
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -84,3 +87,47 @@ func TestStorageEngine_Inhume(t *testing.T) {
|
||||||
require.Empty(t, addrs)
|
require.Empty(t, addrs)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStorageEngine_ECInhume(t *testing.T) {
|
||||||
|
parentObjectAddress := oidtest.Address()
|
||||||
|
containerID := parentObjectAddress.Container()
|
||||||
|
|
||||||
|
chunkObject0 := testutil.GenerateObjectWithCID(containerID)
|
||||||
|
chunkObject0.SetECHeader(objectSDK.NewECHeader(
|
||||||
|
objectSDK.ECParentInfo{
|
||||||
|
ID: parentObjectAddress.Object(),
|
||||||
|
}, 0, 4, []byte{}, 0))
|
||||||
|
|
||||||
|
chunkObject1 := testutil.GenerateObjectWithCID(containerID)
|
||||||
|
chunkObject1.SetECHeader(objectSDK.NewECHeader(
|
||||||
|
objectSDK.ECParentInfo{
|
||||||
|
ID: parentObjectAddress.Object(),
|
||||||
|
}, 1, 4, []byte{}, 0))
|
||||||
|
|
||||||
|
tombstone := objectSDK.NewTombstone()
|
||||||
|
tombstone.SetMembers([]oid.ID{parentObjectAddress.Object()})
|
||||||
|
payload, err := tombstone.Marshal()
|
||||||
|
require.NoError(t, err)
|
||||||
|
tombstoneObject := testutil.GenerateObjectWithCID(containerID)
|
||||||
|
tombstoneObject.SetType(objectSDK.TypeTombstone)
|
||||||
|
tombstoneObject.SetPayload(payload)
|
||||||
|
tombstoneObjectAddress := object.AddressOf(tombstoneObject)
|
||||||
|
|
||||||
|
e := testNewEngine(t).setShardsNum(t, 5).prepare(t).engine
|
||||||
|
defer func() { require.NoError(t, e.Close(context.Background())) }()
|
||||||
|
|
||||||
|
require.NoError(t, Put(context.Background(), e, chunkObject0, false))
|
||||||
|
|
||||||
|
require.NoError(t, Put(context.Background(), e, tombstoneObject, false))
|
||||||
|
|
||||||
|
var inhumePrm InhumePrm
|
||||||
|
inhumePrm.WithTarget(tombstoneObjectAddress, parentObjectAddress)
|
||||||
|
_, err = e.Inhume(context.Background(), inhumePrm)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var alreadyRemoved *apistatus.ObjectAlreadyRemoved
|
||||||
|
|
||||||
|
require.ErrorAs(t, Put(context.Background(), e, chunkObject0, false), &alreadyRemoved)
|
||||||
|
|
||||||
|
require.ErrorAs(t, Put(context.Background(), e, chunkObject1, false), &alreadyRemoved)
|
||||||
|
}
|
||||||
|
|
|
@ -71,21 +71,21 @@ func (e *StorageEngine) put(ctx context.Context, prm PutPrm) error {
|
||||||
|
|
||||||
// In #1146 this check was parallelized, however, it became
|
// In #1146 this check was parallelized, however, it became
|
||||||
// much slower on fast machines for 4 shards.
|
// much slower on fast machines for 4 shards.
|
||||||
var parent oid.Address
|
var ecParent oid.Address
|
||||||
if prm.Object.ECHeader() != nil {
|
if prm.Object.ECHeader() != nil {
|
||||||
parent.SetObject(prm.Object.ECHeader().Parent())
|
ecParent.SetObject(prm.Object.ECHeader().Parent())
|
||||||
parent.SetContainer(addr.Container())
|
ecParent.SetContainer(addr.Container())
|
||||||
}
|
}
|
||||||
var shPrm shard.ExistsPrm
|
var shPrm shard.ExistsPrm
|
||||||
shPrm.Address = addr
|
shPrm.Address = addr
|
||||||
shPrm.ParentAddress = parent
|
shPrm.ECParentAddress = ecParent
|
||||||
existed, locked, err := e.exists(ctx, shPrm)
|
existed, locked, err := e.exists(ctx, shPrm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !existed && locked {
|
if !existed && locked {
|
||||||
lockers, err := e.GetLocked(ctx, parent)
|
lockers, err := e.GetLocked(ctx, ecParent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package meta
|
package meta
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
@ -21,7 +20,7 @@ import (
|
||||||
// ExistsPrm groups the parameters of Exists operation.
|
// ExistsPrm groups the parameters of Exists operation.
|
||||||
type ExistsPrm struct {
|
type ExistsPrm struct {
|
||||||
addr oid.Address
|
addr oid.Address
|
||||||
paddr oid.Address
|
ecParentAddr oid.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExistsRes groups the resulting values of Exists operation.
|
// ExistsRes groups the resulting values of Exists operation.
|
||||||
|
@ -37,9 +36,9 @@ func (p *ExistsPrm) SetAddress(addr oid.Address) {
|
||||||
p.addr = addr
|
p.addr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetParent is an Exists option to set objects parent.
|
// SetECParent is an Exists option to set objects parent.
|
||||||
func (p *ExistsPrm) SetParent(addr oid.Address) {
|
func (p *ExistsPrm) SetECParent(addr oid.Address) {
|
||||||
p.paddr = addr
|
p.ecParentAddr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists returns the fact that the object is in the metabase.
|
// Exists returns the fact that the object is in the metabase.
|
||||||
|
@ -82,7 +81,7 @@ func (db *DB) Exists(ctx context.Context, prm ExistsPrm) (res ExistsRes, err err
|
||||||
currEpoch := db.epochState.CurrentEpoch()
|
currEpoch := db.epochState.CurrentEpoch()
|
||||||
|
|
||||||
err = db.boltDB.View(func(tx *bbolt.Tx) error {
|
err = db.boltDB.View(func(tx *bbolt.Tx) error {
|
||||||
res.exists, res.locked, err = db.exists(tx, prm.addr, prm.paddr, currEpoch)
|
res.exists, res.locked, err = db.exists(tx, prm.addr, prm.ecParentAddr, currEpoch)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
@ -90,10 +89,21 @@ func (db *DB) Exists(ctx context.Context, prm ExistsPrm) (res ExistsRes, err err
|
||||||
return res, metaerr.Wrap(err)
|
return res, metaerr.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) exists(tx *bbolt.Tx, addr oid.Address, parent oid.Address, currEpoch uint64) (bool, bool, error) {
|
func (db *DB) exists(tx *bbolt.Tx, addr oid.Address, ecParent oid.Address, currEpoch uint64) (bool, bool, error) {
|
||||||
var locked bool
|
var locked bool
|
||||||
if !parent.Equals(oid.Address{}) {
|
if !ecParent.Equals(oid.Address{}) {
|
||||||
locked = objectLocked(tx, parent.Container(), parent.Object())
|
st, err := objectStatus(tx, ecParent, currEpoch)
|
||||||
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
switch st {
|
||||||
|
case 2:
|
||||||
|
return false, locked, logicerr.Wrap(new(apistatus.ObjectAlreadyRemoved))
|
||||||
|
case 3:
|
||||||
|
return false, locked, ErrObjectIsExpired
|
||||||
|
}
|
||||||
|
|
||||||
|
locked = objectLocked(tx, ecParent.Container(), ecParent.Object())
|
||||||
}
|
}
|
||||||
// check graveyard and object expiration first
|
// check graveyard and object expiration first
|
||||||
st, err := objectStatus(tx, addr, currEpoch)
|
st, err := objectStatus(tx, addr, currEpoch)
|
||||||
|
@ -216,7 +226,7 @@ func getSplitInfo(tx *bbolt.Tx, cnr cid.ID, key []byte) (*objectSDK.SplitInfo, e
|
||||||
|
|
||||||
splitInfo := objectSDK.NewSplitInfo()
|
splitInfo := objectSDK.NewSplitInfo()
|
||||||
|
|
||||||
err := splitInfo.Unmarshal(bytes.Clone(rawSplitInfo))
|
err := splitInfo.Unmarshal(rawSplitInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't unmarshal split info from root index: %w", err)
|
return nil, fmt.Errorf("can't unmarshal split info from root index: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package meta
|
package meta
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
@ -112,7 +111,7 @@ func (db *DB) get(tx *bbolt.Tx, addr oid.Address, key []byte, checkStatus, raw b
|
||||||
// check in primary index
|
// check in primary index
|
||||||
data := getFromBucket(tx, primaryBucketName(cnr, bucketName), key)
|
data := getFromBucket(tx, primaryBucketName(cnr, bucketName), key)
|
||||||
if len(data) != 0 {
|
if len(data) != 0 {
|
||||||
return obj, obj.Unmarshal(bytes.Clone(data))
|
return obj, obj.Unmarshal(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
data = getFromBucket(tx, ecInfoBucketName(cnr, bucketName), key)
|
data = getFromBucket(tx, ecInfoBucketName(cnr, bucketName), key)
|
||||||
|
@ -123,13 +122,13 @@ func (db *DB) get(tx *bbolt.Tx, addr oid.Address, key []byte, checkStatus, raw b
|
||||||
// if not found then check in tombstone index
|
// if not found then check in tombstone index
|
||||||
data = getFromBucket(tx, tombstoneBucketName(cnr, bucketName), key)
|
data = getFromBucket(tx, tombstoneBucketName(cnr, bucketName), key)
|
||||||
if len(data) != 0 {
|
if len(data) != 0 {
|
||||||
return obj, obj.Unmarshal(bytes.Clone(data))
|
return obj, obj.Unmarshal(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not found then check in locker index
|
// if not found then check in locker index
|
||||||
data = getFromBucket(tx, bucketNameLockers(cnr, bucketName), key)
|
data = getFromBucket(tx, bucketNameLockers(cnr, bucketName), key)
|
||||||
if len(data) != 0 {
|
if len(data) != 0 {
|
||||||
return obj, obj.Unmarshal(bytes.Clone(data))
|
return obj, obj.Unmarshal(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not found then check if object is a virtual
|
// if not found then check if object is a virtual
|
||||||
|
@ -185,7 +184,7 @@ func getVirtualObject(tx *bbolt.Tx, cnr cid.ID, key []byte, raw bool) (*objectSD
|
||||||
|
|
||||||
child := objectSDK.New()
|
child := objectSDK.New()
|
||||||
|
|
||||||
err = child.Unmarshal(bytes.Clone(data))
|
err = child.Unmarshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't unmarshal child with parent: %w", err)
|
return nil, fmt.Errorf("can't unmarshal child with parent: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -219,7 +218,7 @@ func getECInfoError(tx *bbolt.Tx, cnr cid.ID, data []byte) error {
|
||||||
objData := getFromBucket(tx, primaryBucketName(cnr, make([]byte, bucketKeySize)), key)
|
objData := getFromBucket(tx, primaryBucketName(cnr, make([]byte, bucketKeySize)), key)
|
||||||
if len(objData) != 0 {
|
if len(objData) != 0 {
|
||||||
obj := objectSDK.New()
|
obj := objectSDK.New()
|
||||||
if err := obj.Unmarshal(bytes.Clone(objData)); err != nil {
|
if err := obj.Unmarshal(objData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
chunk := objectSDK.ECChunk{}
|
chunk := objectSDK.ECChunk{}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package meta
|
package meta
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -195,7 +194,7 @@ func iteratePhyObjects(tx *bbolt.Tx, f func(cid.ID, oid.ID, *objectSDK.Object) e
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.ForEach(func(k, v []byte) error {
|
return b.ForEach(func(k, v []byte) error {
|
||||||
if oid.Decode(k) == nil && obj.Unmarshal(bytes.Clone(v)) == nil {
|
if oid.Decode(k) == nil && obj.Unmarshal(v) == nil {
|
||||||
return f(cid, oid, obj)
|
return f(cid, oid, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,7 +247,7 @@ func selectNFromBucket(bkt *bbolt.Bucket, // main bucket
|
||||||
var ecInfo *objectcore.ECInfo
|
var ecInfo *objectcore.ECInfo
|
||||||
if objType == objectSDK.TypeRegular {
|
if objType == objectSDK.TypeRegular {
|
||||||
var o objectSDK.Object
|
var o objectSDK.Object
|
||||||
if err := o.Unmarshal(bytes.Clone(v)); err != nil {
|
if err := o.Unmarshal(v); err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
isLinkingObj = isLinkObject(&o)
|
isLinkingObj = isLinkObject(&o)
|
||||||
|
@ -413,7 +413,7 @@ func (db *DB) iterateOverObjectsInContainer(ctx context.Context, tx *bbolt.Tx, p
|
||||||
var ecInfo *objectcore.ECInfo
|
var ecInfo *objectcore.ECInfo
|
||||||
if prm.ObjectType == objectSDK.TypeRegular {
|
if prm.ObjectType == objectSDK.TypeRegular {
|
||||||
var o objectSDK.Object
|
var o objectSDK.Object
|
||||||
if err := o.Unmarshal(bytes.Clone(v)); err != nil {
|
if err := o.Unmarshal(v); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
isLinkingObj = isLinkObject(&o)
|
isLinkingObj = isLinkObject(&o)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package meta
|
package meta
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -121,9 +120,15 @@ func (db *DB) put(tx *bbolt.Tx,
|
||||||
return PutRes{}, errors.New("missing container in object")
|
return PutRes{}, errors.New("missing container in object")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ecParentAddress oid.Address
|
||||||
|
if ecHeader := obj.ECHeader(); ecHeader != nil {
|
||||||
|
ecParentAddress.SetContainer(cnr)
|
||||||
|
ecParentAddress.SetObject(ecHeader.Parent())
|
||||||
|
}
|
||||||
|
|
||||||
isParent := si != nil
|
isParent := si != nil
|
||||||
|
|
||||||
exists, _, err := db.exists(tx, objectCore.AddressOf(obj), oid.Address{}, currEpoch)
|
exists, _, err := db.exists(tx, objectCore.AddressOf(obj), ecParentAddress, currEpoch)
|
||||||
|
|
||||||
var splitInfoError *objectSDK.SplitInfoError
|
var splitInfoError *objectSDK.SplitInfoError
|
||||||
if errors.As(err, &splitInfoError) {
|
if errors.As(err, &splitInfoError) {
|
||||||
|
@ -314,7 +319,7 @@ func updateSplitInfoIndex(tx *bbolt.Tx, objKey []byte, cnr cid.ID, bucketName []
|
||||||
return si.Marshal()
|
return si.Marshal()
|
||||||
default:
|
default:
|
||||||
oldSI := objectSDK.NewSplitInfo()
|
oldSI := objectSDK.NewSplitInfo()
|
||||||
if err := oldSI.Unmarshal(bytes.Clone(old)); err != nil {
|
if err := oldSI.Unmarshal(old); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
si = util.MergeSplitInfo(si, oldSI)
|
si = util.MergeSplitInfo(si, oldSI)
|
||||||
|
|
|
@ -18,7 +18,7 @@ type ExistsPrm struct {
|
||||||
// Exists option to set object checked for existence.
|
// Exists option to set object checked for existence.
|
||||||
Address oid.Address
|
Address oid.Address
|
||||||
// Exists option to set parent object checked for existence.
|
// Exists option to set parent object checked for existence.
|
||||||
ParentAddress oid.Address
|
ECParentAddress oid.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExistsRes groups the resulting values of Exists operation.
|
// ExistsRes groups the resulting values of Exists operation.
|
||||||
|
@ -74,7 +74,7 @@ func (s *Shard) Exists(ctx context.Context, prm ExistsPrm) (ExistsRes, error) {
|
||||||
} else {
|
} else {
|
||||||
var existsPrm meta.ExistsPrm
|
var existsPrm meta.ExistsPrm
|
||||||
existsPrm.SetAddress(prm.Address)
|
existsPrm.SetAddress(prm.Address)
|
||||||
existsPrm.SetParent(prm.ParentAddress)
|
existsPrm.SetECParent(prm.ECParentAddress)
|
||||||
|
|
||||||
var res meta.ExistsRes
|
var res meta.ExistsRes
|
||||||
res, err = s.metaBase.Exists(ctx, existsPrm)
|
res, err = s.metaBase.Exists(ctx, existsPrm)
|
||||||
|
|
|
@ -6,6 +6,9 @@ import (
|
||||||
containersvc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/container"
|
containersvc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container"
|
||||||
containerGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container/grpc"
|
containerGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container/grpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server wraps FrostFS API Container service and
|
// Server wraps FrostFS API Container service and
|
||||||
|
@ -80,3 +83,7 @@ func (s *Server) List(ctx context.Context, req *containerGRPC.ListRequest) (*con
|
||||||
|
|
||||||
return resp.ToGRPCMessage().(*containerGRPC.ListResponse), nil
|
return resp.ToGRPCMessage().(*containerGRPC.ListResponse), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListStream(_ *containerGRPC.ListStreamRequest, _ grpc.ServerStreamingServer[containerGRPC.ListStreamResponse]) error {
|
||||||
|
return status.Error(codes.Unimplemented, "method ListStream not implemented")
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
@ -104,14 +103,7 @@ func (c *checkerCoreImpl) CheckAPE(prm CheckPrm) error {
|
||||||
if found && status == apechain.Allow {
|
if found && status == apechain.Allow {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err = fmt.Errorf("access to operation %s is denied by access policy engine: %s", prm.Request.Operation(), status.String())
|
return newChainRouterError(prm.Request.Operation(), status)
|
||||||
return apeErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func apeErr(err error) error {
|
|
||||||
errAccessDenied := &apistatus.ObjectAccessDenied{}
|
|
||||||
errAccessDenied.WriteReason(err.Error())
|
|
||||||
return errAccessDenied
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValidBearer checks whether bearer token was correctly signed by authorized
|
// isValidBearer checks whether bearer token was correctly signed by authorized
|
||||||
|
|
33
pkg/services/common/ape/error.go
Normal file
33
pkg/services/common/ape/error.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package ape
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChainRouterError is returned when chain router validation prevents
|
||||||
|
// the APE request from being processed (no rule found, access denied, etc.).
|
||||||
|
type ChainRouterError struct {
|
||||||
|
operation string
|
||||||
|
status apechain.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ChainRouterError) Error() string {
|
||||||
|
return fmt.Sprintf("access to operation %s is denied by access policy engine: %s", e.Operation(), e.Status())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ChainRouterError) Operation() string {
|
||||||
|
return e.operation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ChainRouterError) Status() apechain.Status {
|
||||||
|
return e.status
|
||||||
|
}
|
||||||
|
|
||||||
|
func newChainRouterError(operation string, status apechain.Status) *ChainRouterError {
|
||||||
|
return &ChainRouterError{
|
||||||
|
operation: operation,
|
||||||
|
status: status,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,19 @@
|
||||||
package ape
|
package ape
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
checkercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/common/ape"
|
||||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toStatusErr(err error) error {
|
func toStatusErr(err error) error {
|
||||||
|
var chRouterErr *checkercore.ChainRouterError
|
||||||
|
if !errors.As(err, &chRouterErr) {
|
||||||
|
errServerInternal := &apistatus.ServerInternal{}
|
||||||
|
apistatus.WriteInternalServerErr(errServerInternal, err)
|
||||||
|
return errServerInternal
|
||||||
|
}
|
||||||
errAccessDenied := &apistatus.ObjectAccessDenied{}
|
errAccessDenied := &apistatus.ObjectAccessDenied{}
|
||||||
errAccessDenied.WriteReason("ape denied request: " + err.Error())
|
errAccessDenied.WriteReason("ape denied request: " + err.Error())
|
||||||
return errAccessDenied
|
return errAccessDenied
|
||||||
|
|
|
@ -162,13 +162,13 @@ func (s *searchStreamMsgSizeCtrl) Send(resp *object.SearchResponse) error {
|
||||||
|
|
||||||
var newResp *object.SearchResponse
|
var newResp *object.SearchResponse
|
||||||
|
|
||||||
for ln := uint64(len(ids)); ; {
|
for {
|
||||||
if newResp == nil {
|
if newResp == nil {
|
||||||
newResp = new(object.SearchResponse)
|
newResp = new(object.SearchResponse)
|
||||||
newResp.SetBody(body)
|
newResp.SetBody(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
cut := min(s.addrAmount, ln)
|
cut := min(s.addrAmount, uint64(len(ids)))
|
||||||
|
|
||||||
body.SetIDList(ids[:cut])
|
body.SetIDList(ids[:cut])
|
||||||
newResp.SetMetaHeader(resp.GetMetaHeader())
|
newResp.SetMetaHeader(resp.GetMetaHeader())
|
||||||
|
|
|
@ -85,7 +85,10 @@ func TestContainerNodesCache(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("the error is propagated", func(t *testing.T) {
|
t.Run("the error is propagated", func(t *testing.T) {
|
||||||
var pp netmapSDK.PlacementPolicy
|
var pp netmapSDK.PlacementPolicy
|
||||||
require.NoError(t, pp.DecodeString("REP 1 SELECT 1 FROM X FILTER ATTR EQ 42 AS X"))
|
r := netmapSDK.ReplicaDescriptor{}
|
||||||
|
r.SetNumberOfObjects(1)
|
||||||
|
r.SetSelectorName("Missing")
|
||||||
|
pp.AddReplicas(r)
|
||||||
|
|
||||||
c := placement.NewContainerNodesCache(size)
|
c := placement.NewContainerNodesCache(size)
|
||||||
_, err := c.ContainerNodes(nm(1, nodes[0:1]), cidtest.ID(), pp)
|
_, err := c.ContainerNodes(nm(1, nodes[0:1]), cidtest.ID(), pp)
|
||||||
|
|
|
@ -202,7 +202,7 @@ func sortVector(cfg *cfg, unsortedVector []netmap.NodeInfo) ([]netmap.NodeInfo,
|
||||||
metrics: m,
|
metrics: m,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slices.SortFunc(nm, func(a, b nodeMetrics) int {
|
slices.SortStableFunc(nm, func(a, b nodeMetrics) int {
|
||||||
return slices.Compare(a.metrics, b.metrics)
|
return slices.Compare(a.metrics, b.metrics)
|
||||||
})
|
})
|
||||||
sortedVector := make([]netmap.NodeInfo, len(unsortedVector))
|
sortedVector := make([]netmap.NodeInfo, len(unsortedVector))
|
||||||
|
|
|
@ -281,6 +281,8 @@ func (p *Policer) adjustECPlacement(ctx context.Context, objInfo objectcore.Info
|
||||||
}
|
}
|
||||||
chunkIDs[ch.Index] = ecInfoChunkID
|
chunkIDs[ch.Index] = ecInfoChunkID
|
||||||
}
|
}
|
||||||
|
} else if client.IsErrObjectAlreadyRemoved(err) {
|
||||||
|
restore = false
|
||||||
} else if !p.cfg.netmapKeys.IsLocalKey(n.PublicKey()) && uint32(idx) < objInfo.ECInfo.Total {
|
} else if !p.cfg.netmapKeys.IsLocalKey(n.PublicKey()) && uint32(idx) < objInfo.ECInfo.Total {
|
||||||
p.log.Warn(ctx, logs.PolicerCouldNotGetObjectFromNodeMoving, zap.String("node", hex.EncodeToString(n.PublicKey())), zap.Stringer("object", parentAddress), zap.Error(err))
|
p.log.Warn(ctx, logs.PolicerCouldNotGetObjectFromNodeMoving, zap.String("node", hex.EncodeToString(n.PublicKey())), zap.Stringer("object", parentAddress), zap.Error(err))
|
||||||
p.replicator.HandleReplicationTask(ctx, replicator.Task{
|
p.replicator.HandleReplicationTask(ctx, replicator.Task{
|
||||||
|
|
|
@ -9,8 +9,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
core "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
core "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||||
|
checkercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/common/ape"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||||
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
||||||
|
@ -62,7 +64,22 @@ func (s *Service) verifyClient(ctx context.Context, req message, cid cidSDK.ID,
|
||||||
return fmt.Errorf("can't get request role: %w", err)
|
return fmt.Errorf("can't get request role: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.checkAPE(ctx, bt, cnr, cid, op, role, pubKey)
|
if err = s.checkAPE(ctx, bt, cnr, cid, op, role, pubKey); err != nil {
|
||||||
|
return apeErr(err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func apeErr(err error) error {
|
||||||
|
var chRouterErr *checkercore.ChainRouterError
|
||||||
|
if !errors.As(err, &chRouterErr) {
|
||||||
|
errServerInternal := &apistatus.ServerInternal{}
|
||||||
|
apistatus.WriteInternalServerErr(errServerInternal, err)
|
||||||
|
return errServerInternal
|
||||||
|
}
|
||||||
|
errAccessDenied := &apistatus.ObjectAccessDenied{}
|
||||||
|
errAccessDenied.WriteReason(err.Error())
|
||||||
|
return errAccessDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff the operation is read-only and request was signed
|
// Returns true iff the operation is read-only and request was signed
|
||||||
|
|
Loading…
Reference in a new issue