forked from TrueCloudLab/frostfs-node
[#11] Trim the old functionality
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
783ec72d56
commit
a87fdab324
235 changed files with 39 additions and 35111 deletions
|
@ -1,314 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/morph"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func setDefaults(v *viper.Viper) {
|
|
||||||
// Logger section
|
|
||||||
{
|
|
||||||
v.SetDefault("logger.level", "debug")
|
|
||||||
v.SetDefault("logger.format", "console")
|
|
||||||
v.SetDefault("logger.trace_level", "fatal")
|
|
||||||
v.SetDefault("logger.no_disclaimer", false) // to disable app_name and app_version
|
|
||||||
|
|
||||||
v.SetDefault("logger.sampling.initial", 1000) // todo: add description
|
|
||||||
v.SetDefault("logger.sampling.thereafter", 1000) // todo: add description
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transport section
|
|
||||||
{
|
|
||||||
v.SetDefault("transport.attempts_count", 5)
|
|
||||||
v.SetDefault("transport.attempts_ttl", "30s")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peers section
|
|
||||||
{
|
|
||||||
v.SetDefault("peers.metrics_timeout", "5s")
|
|
||||||
v.SetDefault("peers.connections_ttl", "30s")
|
|
||||||
v.SetDefault("peers.connections_idle", "30s")
|
|
||||||
v.SetDefault("peers.keep_alive.ttl", "30s")
|
|
||||||
v.SetDefault("peers.keep_alive.ping", "100ms")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Muxer session
|
|
||||||
{
|
|
||||||
v.SetDefault("muxer.http.read_buffer_size", 0)
|
|
||||||
v.SetDefault("muxer.http.write_buffer_size", 0)
|
|
||||||
v.SetDefault("muxer.http.read_timeout", 0)
|
|
||||||
v.SetDefault("muxer.http.write_timeout", 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Node section
|
|
||||||
{
|
|
||||||
v.SetDefault("node.proto", "tcp") // tcp or udp
|
|
||||||
v.SetDefault("node.address", ":8080")
|
|
||||||
v.SetDefault("node.shutdown_ttl", "30s")
|
|
||||||
v.SetDefault("node.private_key", "keys/node_00.key")
|
|
||||||
|
|
||||||
v.SetDefault("node.grpc.logging", true)
|
|
||||||
v.SetDefault("node.grpc.metrics", true)
|
|
||||||
v.SetDefault("node.grpc.billing", true)
|
|
||||||
|
|
||||||
// Contains public keys, which can send requests to state.DumpConfig
|
|
||||||
// for now, in the future, should be replaced with ACL or something else.
|
|
||||||
v.SetDefault("node.rpc.owners", []string{
|
|
||||||
// By default we add user.key
|
|
||||||
// TODO should be removed before public release:
|
|
||||||
// or add into default Dockerfile `NEOFS_NODE_RPC_OWNERS_0=`
|
|
||||||
"031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4a",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Object section
|
|
||||||
{
|
|
||||||
v.SetDefault("object.max_processing_size", 100) // size in MB, use 0 to remove restriction
|
|
||||||
v.SetDefault("object.workers_count", 5)
|
|
||||||
v.SetDefault("object.assembly", true)
|
|
||||||
v.SetDefault("object.window_size", 3)
|
|
||||||
|
|
||||||
v.SetDefault("object.transformers.payload_limiter.max_payload_size", 5000) // size in KB
|
|
||||||
|
|
||||||
// algorithm used for salt applying in range hash, for now only xor is available
|
|
||||||
v.SetDefault("object.salitor", "xor")
|
|
||||||
|
|
||||||
// set true to check container ACL rules
|
|
||||||
v.SetDefault("object.check_acl", true)
|
|
||||||
|
|
||||||
v.SetDefault("object.dial_timeout", "500ms")
|
|
||||||
rpcs := []string{"put", "get", "delete", "head", "search", "range", "range_hash"}
|
|
||||||
for i := range rpcs {
|
|
||||||
v.SetDefault("object."+rpcs[i]+".timeout", "5s")
|
|
||||||
v.SetDefault("object."+rpcs[i]+".log_errs", false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replication section
|
|
||||||
{
|
|
||||||
v.SetDefault("replication.manager.pool_size", 100)
|
|
||||||
v.SetDefault("replication.manager.pool_expansion_rate", 0.1)
|
|
||||||
v.SetDefault("replication.manager.read_pool_interval", "500ms")
|
|
||||||
v.SetDefault("replication.manager.push_task_timeout", "1s")
|
|
||||||
v.SetDefault("replication.manager.placement_honorer_enabled", true)
|
|
||||||
v.SetDefault("replication.manager.capacities.replicate", 1)
|
|
||||||
v.SetDefault("replication.manager.capacities.restore", 1)
|
|
||||||
v.SetDefault("replication.manager.capacities.garbage", 1)
|
|
||||||
|
|
||||||
v.SetDefault("replication.placement_honorer.chan_capacity", 1)
|
|
||||||
v.SetDefault("replication.placement_honorer.result_timeout", "1s")
|
|
||||||
v.SetDefault("replication.placement_honorer.timeouts.put", "5s")
|
|
||||||
v.SetDefault("replication.placement_honorer.timeouts.get", "5s")
|
|
||||||
|
|
||||||
v.SetDefault("replication.location_detector.chan_capacity", 1)
|
|
||||||
v.SetDefault("replication.location_detector.result_timeout", "1s")
|
|
||||||
v.SetDefault("replication.location_detector.timeouts.search", "5s")
|
|
||||||
|
|
||||||
v.SetDefault("replication.storage_validator.chan_capacity", 1)
|
|
||||||
v.SetDefault("replication.storage_validator.result_timeout", "1s")
|
|
||||||
v.SetDefault("replication.storage_validator.salt_size", 64) // size in bytes
|
|
||||||
v.SetDefault("replication.storage_validator.max_payload_range_size", 64) // size in bytes
|
|
||||||
v.SetDefault("replication.storage_validator.payload_range_count", 3)
|
|
||||||
v.SetDefault("replication.storage_validator.salitor", "xor")
|
|
||||||
v.SetDefault("replication.storage_validator.timeouts.get", "5s")
|
|
||||||
v.SetDefault("replication.storage_validator.timeouts.head", "5s")
|
|
||||||
v.SetDefault("replication.storage_validator.timeouts.range_hash", "5s")
|
|
||||||
|
|
||||||
v.SetDefault("replication.replicator.chan_capacity", 1)
|
|
||||||
v.SetDefault("replication.replicator.result_timeout", "1s")
|
|
||||||
v.SetDefault("replication.replicator.timeouts.put", "5s")
|
|
||||||
|
|
||||||
v.SetDefault("replication.restorer.chan_capacity", 1)
|
|
||||||
v.SetDefault("replication.restorer.result_timeout", "1s")
|
|
||||||
v.SetDefault("replication.restorer.timeouts.get", "5s")
|
|
||||||
v.SetDefault("replication.restorer.timeouts.head", "5s")
|
|
||||||
}
|
|
||||||
|
|
||||||
// PPROF section
|
|
||||||
{
|
|
||||||
v.SetDefault("pprof.enabled", true)
|
|
||||||
v.SetDefault("pprof.address", ":6060")
|
|
||||||
v.SetDefault("pprof.shutdown_ttl", "10s")
|
|
||||||
// v.SetDefault("pprof.read_timeout", "10s")
|
|
||||||
// v.SetDefault("pprof.read_header_timeout", "10s")
|
|
||||||
// v.SetDefault("pprof.write_timeout", "10s")
|
|
||||||
// v.SetDefault("pprof.idle_timeout", "10s")
|
|
||||||
// v.SetDefault("pprof.max_header_bytes", 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metrics section
|
|
||||||
{
|
|
||||||
v.SetDefault("metrics.enabled", true)
|
|
||||||
v.SetDefault("metrics.address", ":8090")
|
|
||||||
v.SetDefault("metrics.shutdown_ttl", "10s")
|
|
||||||
// v.SetDefault("metrics.read_header_timeout", "10s")
|
|
||||||
// v.SetDefault("metrics.write_timeout", "10s")
|
|
||||||
// v.SetDefault("metrics.idle_timeout", "10s")
|
|
||||||
// v.SetDefault("metrics.max_header_bytes", 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workers section
|
|
||||||
{
|
|
||||||
workers := []string{
|
|
||||||
"peers",
|
|
||||||
"boot",
|
|
||||||
"replicator",
|
|
||||||
"metrics",
|
|
||||||
"event_listener",
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range workers {
|
|
||||||
v.SetDefault("workers."+workers[i]+".immediately", true)
|
|
||||||
v.SetDefault("workers."+workers[i]+".disabled", false)
|
|
||||||
// v.SetDefault("workers."+workers[i]+".timer", "5s") // run worker every 5sec and reset timer after job
|
|
||||||
// v.SetDefault("workers."+workers[i]+".ticker", "5s") // run worker every 5sec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Morph section
|
|
||||||
{
|
|
||||||
|
|
||||||
// Endpoint
|
|
||||||
v.SetDefault(
|
|
||||||
morph.EndpointOptPath(),
|
|
||||||
"http://morph_chain.localtest.nspcc.ru:30333",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Dial timeout
|
|
||||||
v.SetDefault(
|
|
||||||
morph.DialTimeoutOptPath(),
|
|
||||||
5*time.Second,
|
|
||||||
)
|
|
||||||
|
|
||||||
v.SetDefault(
|
|
||||||
morph.MagicNumberOptPath(),
|
|
||||||
uint32(netmode.PrivNet),
|
|
||||||
)
|
|
||||||
|
|
||||||
{ // Event listener
|
|
||||||
// Endpoint
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ListenerEndpointOptPath(),
|
|
||||||
"ws://morph_chain.localtest.nspcc.ru:30333/ws",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Dial timeout
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ListenerDialTimeoutOptPath(),
|
|
||||||
5*time.Second,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Common parameters
|
|
||||||
for _, name := range morph.ContractNames {
|
|
||||||
// Script hash
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ScriptHashOptPath(name),
|
|
||||||
"c77ecae9773ad0c619ad59f7f2dd6f585ddc2e70", // LE
|
|
||||||
)
|
|
||||||
|
|
||||||
// Invocation fee
|
|
||||||
v.SetDefault(
|
|
||||||
morph.InvocationFeeOptPath(name),
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Container
|
|
||||||
// Set EACL method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ContainerContractSetEACLOptPath(),
|
|
||||||
"SetEACL",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get EACL method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ContainerContractEACLOptPath(),
|
|
||||||
"EACL",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Put method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ContainerContractPutOptPath(),
|
|
||||||
"Put",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ContainerContractGetOptPath(),
|
|
||||||
"Get",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Delete method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ContainerContractDelOptPath(),
|
|
||||||
"Delete",
|
|
||||||
)
|
|
||||||
|
|
||||||
// List method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ContainerContractListOptPath(),
|
|
||||||
"List",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Netmap
|
|
||||||
// AddPeer method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.NetmapContractAddPeerOptPath(),
|
|
||||||
"AddPeer",
|
|
||||||
)
|
|
||||||
|
|
||||||
// New epoch method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.NetmapContractNewEpochOptPath(),
|
|
||||||
"NewEpoch",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Netmap method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.NetmapContractNetmapOptPath(),
|
|
||||||
"Netmap",
|
|
||||||
)
|
|
||||||
|
|
||||||
// Update state method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.NetmapContractUpdateStateOptPath(),
|
|
||||||
"UpdateState",
|
|
||||||
)
|
|
||||||
|
|
||||||
// IR list method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.NetmapContractIRListOptPath(),
|
|
||||||
"InnerRingList",
|
|
||||||
)
|
|
||||||
|
|
||||||
// New epoch event type
|
|
||||||
v.SetDefault(
|
|
||||||
morph.ContractEventOptPath(
|
|
||||||
morph.NetmapContractName,
|
|
||||||
morph.NewEpochEventType,
|
|
||||||
),
|
|
||||||
"NewEpoch",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Balance
|
|
||||||
// balanceOf method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.BalanceContractBalanceOfOptPath(),
|
|
||||||
"balanceOf",
|
|
||||||
)
|
|
||||||
|
|
||||||
// decimals method name
|
|
||||||
v.SetDefault(
|
|
||||||
morph.BalanceContractDecimalsOfOptPath(),
|
|
||||||
"decimals",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,146 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"github.com/nspcc-dev/neofs-node/pkg/util/grace"
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/service"
|
|
||||||
state2 "github.com/nspcc-dev/neofs-api-go/state"
|
|
||||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/config"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/worker"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/node"
|
|
||||||
"github.com/nspcc-dev/neofs-node/misc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/muxer"
|
|
||||||
statesrv "github.com/nspcc-dev/neofs-node/pkg/network/transport/state/grpc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/profiler"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type params struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Debug profiler.Profiler `optional:"true"`
|
|
||||||
Metric profiler.Metrics `optional:"true"`
|
|
||||||
Worker worker.Workers `optional:"true"`
|
|
||||||
Muxer muxer.Mux
|
|
||||||
Logger *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
healthCheck bool
|
|
||||||
configFile string
|
|
||||||
)
|
|
||||||
|
|
||||||
func runner(ctx context.Context, p params) error {
|
|
||||||
// create combined service, that would start/stop all
|
|
||||||
svc := fix.NewServices(p.Debug, p.Metric, p.Muxer, p.Worker)
|
|
||||||
|
|
||||||
p.Logger.Info("start services")
|
|
||||||
svc.Start(ctx)
|
|
||||||
|
|
||||||
<-ctx.Done()
|
|
||||||
|
|
||||||
p.Logger.Info("stop services")
|
|
||||||
svc.Stop()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func check(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: this is a copypaste from node settings constructor
|
|
||||||
func keyFromCfg(v *viper.Viper) (*ecdsa.PrivateKey, error) {
|
|
||||||
switch key := v.GetString("node.private_key"); key {
|
|
||||||
case "":
|
|
||||||
return nil, errors.New("`node.private_key` could not be empty")
|
|
||||||
case "generated":
|
|
||||||
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
||||||
default:
|
|
||||||
return crypto.LoadPrivateKey(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runHealthCheck() {
|
|
||||||
if !healthCheck {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
cfg, err := config.NewConfig(config.Params{
|
|
||||||
File: configFile,
|
|
||||||
Prefix: misc.Prefix,
|
|
||||||
Name: misc.NodeName,
|
|
||||||
Version: misc.Version,
|
|
||||||
|
|
||||||
AppDefaults: setDefaults,
|
|
||||||
})
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
addr := cfg.GetString("node.address")
|
|
||||||
|
|
||||||
key, err := keyFromCfg(cfg)
|
|
||||||
if err != nil {
|
|
||||||
check(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
con, err := grpc.DialContext(ctx, addr,
|
|
||||||
// TODO: we must provide grpc.WithInsecure() or set credentials
|
|
||||||
grpc.WithInsecure())
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
req := new(statesrv.HealthRequest)
|
|
||||||
req.SetTTL(service.NonForwardingTTL)
|
|
||||||
if err := service.SignRequestData(key, req); err != nil {
|
|
||||||
check(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := state2.NewStatusClient(con).
|
|
||||||
HealthCheck(ctx, req)
|
|
||||||
check(errors.Wrapf(err, "address: %q", addr))
|
|
||||||
|
|
||||||
var exitCode int
|
|
||||||
|
|
||||||
if !res.Healthy {
|
|
||||||
exitCode = 2
|
|
||||||
}
|
|
||||||
_, _ = os.Stdout.Write([]byte(res.Status + "\n"))
|
|
||||||
os.Exit(exitCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.BoolVar(&healthCheck, "health", healthCheck, "run health-check")
|
ctx := grace.NewGracefulContext(nil)
|
||||||
|
|
||||||
// todo: if configFile is empty, we can check './config.yml' manually
|
<-ctx.Done()
|
||||||
flag.StringVar(&configFile, "config", configFile, "use config.yml file")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
runHealthCheck()
|
|
||||||
|
|
||||||
fix.New(&fix.Settings{
|
|
||||||
File: configFile,
|
|
||||||
Name: misc.NodeName,
|
|
||||||
Prefix: misc.Prefix,
|
|
||||||
Runner: runner,
|
|
||||||
Build: misc.Build,
|
|
||||||
Version: misc.Version,
|
|
||||||
|
|
||||||
AppDefaults: setDefaults,
|
|
||||||
}, node.Module).RunAndCatch()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
package bootstrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"errors"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
|
|
||||||
state "github.com/nspcc-dev/neofs-node/pkg/network/transport/state/grpc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
healthyParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
Viper *viper.Viper
|
|
||||||
Place placement.Component
|
|
||||||
Checkers []state.HealthChecker `group:"healthy"`
|
|
||||||
|
|
||||||
// for ChangeState
|
|
||||||
PrivateKey *ecdsa.PrivateKey
|
|
||||||
|
|
||||||
Client *contract.Wrapper
|
|
||||||
}
|
|
||||||
|
|
||||||
healthyResult struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
HealthyClient HealthyClient
|
|
||||||
|
|
||||||
StateService state.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthyClient is an interface of healthiness checking tool.
|
|
||||||
HealthyClient interface {
|
|
||||||
Healthy() error
|
|
||||||
}
|
|
||||||
|
|
||||||
healthyClient struct {
|
|
||||||
*sync.RWMutex
|
|
||||||
healthy func() error
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var errUnhealthy = errors.New("unhealthy")
|
|
||||||
|
|
||||||
func (h *healthyClient) setHandler(handler func() error) {
|
|
||||||
if handler == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.Lock()
|
|
||||||
h.healthy = handler
|
|
||||||
h.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *healthyClient) Healthy() error {
|
|
||||||
if h.healthy == nil {
|
|
||||||
return errUnhealthy
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.healthy()
|
|
||||||
}
|
|
||||||
|
|
||||||
func newHealthy(p healthyParams) (res healthyResult, err error) {
|
|
||||||
sp := state.Params{
|
|
||||||
Stater: p.Place,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Viper: p.Viper,
|
|
||||||
Checkers: p.Checkers,
|
|
||||||
PrivateKey: p.PrivateKey,
|
|
||||||
Client: p.Client,
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.StateService, err = state.New(sp); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
healthyClient := &healthyClient{
|
|
||||||
RWMutex: new(sync.RWMutex),
|
|
||||||
}
|
|
||||||
|
|
||||||
healthyClient.setHandler(res.StateService.Healthy)
|
|
||||||
|
|
||||||
res.HealthyClient = healthyClient
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package bootstrap
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/module"
|
|
||||||
|
|
||||||
// Module is a module of bootstrap component.
|
|
||||||
var Module = module.Module{
|
|
||||||
{Constructor: newHealthy},
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package fix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (a *app) Catch(err error) {
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.log == nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.log.Fatal("Can't run app",
|
|
||||||
zap.Error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CatchTrace catch errors for debugging
|
|
||||||
// use that function just for debug your application.
|
|
||||||
func (a *app) CatchTrace(err error) {
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// digging into the root of the problem
|
|
||||||
for {
|
|
||||||
var (
|
|
||||||
ok bool
|
|
||||||
v = reflect.ValueOf(err)
|
|
||||||
fn reflect.Value
|
|
||||||
)
|
|
||||||
|
|
||||||
if v.Type().Kind() != reflect.Struct {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if !v.FieldByName("Reason").IsValid() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.FieldByName("Func").IsValid() {
|
|
||||||
fn = v.FieldByName("Func")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Place: %#v\nReason: %s\n\n", fn, err)
|
|
||||||
|
|
||||||
if err, ok = v.FieldByName("Reason").Interface().(error); !ok {
|
|
||||||
err = v.Interface().(error)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
panic(err)
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Params groups the parameters of configuration.
|
|
||||||
type Params struct {
|
|
||||||
File string
|
|
||||||
Type string
|
|
||||||
Prefix string
|
|
||||||
Name string
|
|
||||||
Version string
|
|
||||||
|
|
||||||
AppDefaults func(v *viper.Viper)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConfig is a configuration tool's constructor.
|
|
||||||
func NewConfig(p Params) (v *viper.Viper, err error) {
|
|
||||||
v = viper.New()
|
|
||||||
v.SetEnvPrefix(p.Prefix)
|
|
||||||
v.AutomaticEnv()
|
|
||||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
||||||
|
|
||||||
v.SetDefault("app.name", p.Name)
|
|
||||||
v.SetDefault("app.version", p.Version)
|
|
||||||
|
|
||||||
if p.AppDefaults != nil {
|
|
||||||
p.AppDefaults(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.fromFile() {
|
|
||||||
v.SetConfigFile(p.File)
|
|
||||||
v.SetConfigType(p.safeType())
|
|
||||||
|
|
||||||
err = v.ReadInConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Params) fromFile() bool {
|
|
||||||
return p.File != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Params) safeType() string {
|
|
||||||
if p.Type == "" {
|
|
||||||
p.Type = "yaml"
|
|
||||||
}
|
|
||||||
return strings.ToLower(p.Type)
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
package fix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/config"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/module"
|
|
||||||
"github.com/nspcc-dev/neofs-node/misc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/grace"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// App is an interface of executable application.
|
|
||||||
App interface {
|
|
||||||
Run() error
|
|
||||||
RunAndCatch()
|
|
||||||
}
|
|
||||||
|
|
||||||
app struct {
|
|
||||||
err error
|
|
||||||
log *zap.Logger
|
|
||||||
di *dig.Container
|
|
||||||
runner interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Settings groups the application parameters.
|
|
||||||
Settings struct {
|
|
||||||
File string
|
|
||||||
Type string
|
|
||||||
Name string
|
|
||||||
Prefix string
|
|
||||||
Build string
|
|
||||||
Version string
|
|
||||||
Runner interface{}
|
|
||||||
|
|
||||||
AppDefaults func(v *viper.Viper)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (a *app) RunAndCatch() {
|
|
||||||
err := a.Run()
|
|
||||||
|
|
||||||
if errors.Is(err, context.Canceled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ok, _ := strconv.ParseBool(misc.Debug); ok {
|
|
||||||
a.CatchTrace(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.Catch(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *app) Run() error {
|
|
||||||
if a.err != nil {
|
|
||||||
return a.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup app logger:
|
|
||||||
if err := a.di.Invoke(func(l *zap.Logger) {
|
|
||||||
a.log = l
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.di.Invoke(a.runner)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New is an application constructor.
|
|
||||||
func New(s *Settings, mod module.Module) App {
|
|
||||||
var (
|
|
||||||
a app
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
a.di = dig.New(dig.DeferAcyclicVerification())
|
|
||||||
a.runner = s.Runner
|
|
||||||
|
|
||||||
if s.Prefix == "" {
|
|
||||||
s.Prefix = s.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
mod = mod.Append(
|
|
||||||
module.Module{
|
|
||||||
{Constructor: logger.NewLogger},
|
|
||||||
{Constructor: grace.NewGracefulContext},
|
|
||||||
{Constructor: func() (*viper.Viper, error) {
|
|
||||||
return config.NewConfig(config.Params{
|
|
||||||
File: s.File,
|
|
||||||
Type: s.Type,
|
|
||||||
Prefix: strings.ToUpper(s.Prefix),
|
|
||||||
Name: s.Name,
|
|
||||||
Version: fmt.Sprintf("%s(%s)", s.Version, s.Build),
|
|
||||||
|
|
||||||
AppDefaults: s.AppDefaults,
|
|
||||||
})
|
|
||||||
}},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err = module.Provide(a.di, mod); err != nil {
|
|
||||||
a.err = err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &a
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package module
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go.uber.org/dig"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Module type
|
|
||||||
Module []*Provider
|
|
||||||
|
|
||||||
// Provider struct
|
|
||||||
Provider struct {
|
|
||||||
Constructor interface{}
|
|
||||||
Options []dig.ProvideOption
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Append module to target module and return new module
|
|
||||||
func (m Module) Append(mods ...Module) Module {
|
|
||||||
var result = m
|
|
||||||
for _, mod := range mods {
|
|
||||||
result = append(result, mod...)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide set providers functions to DI container
|
|
||||||
func Provide(dic *dig.Container, providers Module) error {
|
|
||||||
for _, p := range providers {
|
|
||||||
if err := dic.Provide(p.Constructor, p.Options...); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package fix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Service interface
|
|
||||||
Service interface {
|
|
||||||
Start(context.Context)
|
|
||||||
Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
combiner []Service
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Service = (combiner)(nil)
|
|
||||||
|
|
||||||
// NewServices creates single runner.
|
|
||||||
func NewServices(items ...Service) Service {
|
|
||||||
var svc = make(combiner, 0, len(items))
|
|
||||||
|
|
||||||
for _, item := range items {
|
|
||||||
if item == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
svc = append(svc, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
return svc
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start all services.
|
|
||||||
func (c combiner) Start(ctx context.Context) {
|
|
||||||
for _, svc := range c {
|
|
||||||
svc.Start(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop all services.
|
|
||||||
func (c combiner) Stop() {
|
|
||||||
for _, svc := range c {
|
|
||||||
svc.Stop()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package worker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Workers is an interface of worker tool.
|
|
||||||
Workers interface {
|
|
||||||
Start(context.Context)
|
|
||||||
Stop()
|
|
||||||
|
|
||||||
Add(Job Handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
workers struct {
|
|
||||||
cancel context.CancelFunc
|
|
||||||
started *int32
|
|
||||||
wg *sync.WaitGroup
|
|
||||||
jobs []Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handler is a worker's handling function.
|
|
||||||
Handler func(ctx context.Context)
|
|
||||||
|
|
||||||
// Jobs is a map of worker names to handlers.
|
|
||||||
Jobs map[string]Handler
|
|
||||||
|
|
||||||
// Job groups the parameters of worker's job.
|
|
||||||
Job struct {
|
|
||||||
Disabled bool
|
|
||||||
Immediately bool
|
|
||||||
Timer time.Duration
|
|
||||||
Ticker time.Duration
|
|
||||||
Handler Handler
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// New is a constructor of workers.
|
|
||||||
func New() Workers {
|
|
||||||
return &workers{
|
|
||||||
started: new(int32),
|
|
||||||
wg: new(sync.WaitGroup),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *workers) Add(job Handler) {
|
|
||||||
w.jobs = append(w.jobs, job)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *workers) Stop() {
|
|
||||||
if !atomic.CompareAndSwapInt32(w.started, 1, 0) {
|
|
||||||
// already stopped
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.cancel()
|
|
||||||
w.wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *workers) Start(ctx context.Context) {
|
|
||||||
if !atomic.CompareAndSwapInt32(w.started, 0, 1) {
|
|
||||||
// already started
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, w.cancel = context.WithCancel(ctx)
|
|
||||||
for _, job := range w.jobs {
|
|
||||||
w.wg.Add(1)
|
|
||||||
|
|
||||||
go func(handler Handler) {
|
|
||||||
defer w.wg.Done()
|
|
||||||
handler(ctx)
|
|
||||||
}(job)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,141 +0,0 @@
|
||||||
package grpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/gogo/protobuf/proto"
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
billingStream struct {
|
|
||||||
grpc.ServerStream
|
|
||||||
*grpc.StreamServerInfo
|
|
||||||
|
|
||||||
input int
|
|
||||||
output int
|
|
||||||
cid string
|
|
||||||
}
|
|
||||||
|
|
||||||
cider interface {
|
|
||||||
CID() refs.CID
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
typeInput = "input"
|
|
||||||
typeOutput = "output"
|
|
||||||
|
|
||||||
labelType = "type"
|
|
||||||
labelMethod = "method"
|
|
||||||
labelContainer = "container"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
serviceBillingBytes = prometheus.NewCounterVec(prometheus.CounterOpts{
|
|
||||||
Namespace: "neofs",
|
|
||||||
Name: "billing_bytes",
|
|
||||||
Help: "Count of bytes received / sent for method and container",
|
|
||||||
}, []string{labelType, labelMethod, labelContainer})
|
|
||||||
|
|
||||||
serviceBillingCalls = prometheus.NewCounterVec(prometheus.CounterOpts{
|
|
||||||
Namespace: "neofs",
|
|
||||||
Name: "billing_calls",
|
|
||||||
Help: "Count of calls for api methods",
|
|
||||||
}, []string{labelMethod, labelContainer})
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Register billing metrics
|
|
||||||
prometheus.MustRegister(serviceBillingBytes)
|
|
||||||
prometheus.MustRegister(serviceBillingCalls)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProtoSize(val interface{}) int {
|
|
||||||
if msg, ok := val.(proto.Message); ok && msg != nil {
|
|
||||||
return proto.Size(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func getProtoContainer(val interface{}) string {
|
|
||||||
if t, ok := val.(cider); ok && t != nil {
|
|
||||||
return t.CID().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *billingStream) RecvMsg(msg interface{}) error {
|
|
||||||
err := b.ServerStream.RecvMsg(msg)
|
|
||||||
b.input += getProtoSize(msg)
|
|
||||||
|
|
||||||
if cid := getProtoContainer(msg); cid != "" {
|
|
||||||
b.cid = cid
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *billingStream) SendMsg(msg interface{}) error {
|
|
||||||
b.output += getProtoSize(msg)
|
|
||||||
|
|
||||||
return b.ServerStream.SendMsg(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *billingStream) report() {
|
|
||||||
labels := prometheus.Labels{
|
|
||||||
labelMethod: b.FullMethod,
|
|
||||||
labelContainer: b.cid,
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceBillingCalls.With(labels).Inc()
|
|
||||||
|
|
||||||
labels[labelType] = typeInput
|
|
||||||
serviceBillingBytes.With(labels).Add(float64(b.input))
|
|
||||||
|
|
||||||
labels[labelType] = typeOutput
|
|
||||||
serviceBillingBytes.With(labels).Add(float64(b.output))
|
|
||||||
}
|
|
||||||
|
|
||||||
func streamBilling(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
|
||||||
stream := &billingStream{
|
|
||||||
ServerStream: ss,
|
|
||||||
StreamServerInfo: info,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := handler(srv, stream)
|
|
||||||
|
|
||||||
stream.report()
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func unaryBilling(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (res interface{}, err error) {
|
|
||||||
input := getProtoSize(req)
|
|
||||||
cid := getProtoContainer(req)
|
|
||||||
|
|
||||||
labels := prometheus.Labels{
|
|
||||||
labelMethod: info.FullMethod,
|
|
||||||
labelContainer: cid,
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceBillingCalls.With(labels).Inc()
|
|
||||||
|
|
||||||
if res, err = handler(ctx, req); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
output := getProtoSize(res)
|
|
||||||
|
|
||||||
labels[labelType] = typeInput
|
|
||||||
serviceBillingBytes.With(labels).Add(float64(input))
|
|
||||||
|
|
||||||
labels[labelType] = typeOutput
|
|
||||||
serviceBillingBytes.With(labels).Add(float64(output))
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package grpc
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/module"
|
|
||||||
|
|
||||||
// Module is a gRPC layer module.
|
|
||||||
var Module = module.Module{
|
|
||||||
{Constructor: routing},
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
// About "github.com/nspcc-dev/neofs-node/lib/grpc"
|
|
||||||
// there's just alias for "google.golang.org/grpc"
|
|
||||||
// with Service-interface
|
|
||||||
|
|
||||||
package grpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
|
||||||
gZap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
|
||||||
prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
|
||||||
libgrpc "github.com/nspcc-dev/neofs-node/pkg/network/transport/grpc"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
Service = libgrpc.Service
|
|
||||||
|
|
||||||
// ServerParams to create gRPC-server
|
|
||||||
// and provide service-handlers
|
|
||||||
ServerParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Services []Service
|
|
||||||
Logger *zap.Logger
|
|
||||||
Viper *viper.Viper
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServicesResult ...
|
|
||||||
ServicesResult struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
Services []Service
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server type-alias
|
|
||||||
Server = grpc.Server
|
|
||||||
|
|
||||||
// CallOption type-alias
|
|
||||||
CallOption = grpc.CallOption
|
|
||||||
|
|
||||||
// ClientConn type-alias
|
|
||||||
ClientConn = grpc.ClientConn
|
|
||||||
|
|
||||||
// ServerOption type-alias
|
|
||||||
ServerOption = grpc.ServerOption
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DialContext func-alias
|
|
||||||
DialContext = grpc.DialContext
|
|
||||||
|
|
||||||
// WithBlock func-alias
|
|
||||||
WithBlock = grpc.WithBlock
|
|
||||||
|
|
||||||
// WithInsecure func-alias
|
|
||||||
WithInsecure = grpc.WithInsecure
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewServer creates a gRPC server which has no service registered and has not
|
|
||||||
// started to accept requests yet.
|
|
||||||
func NewServer(opts ...ServerOption) *Server {
|
|
||||||
return grpc.NewServer(opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// creates new gRPC server and attach handlers.
|
|
||||||
func routing(p ServerParams) *grpc.Server {
|
|
||||||
var (
|
|
||||||
options []ServerOption
|
|
||||||
stream []grpc.StreamServerInterceptor
|
|
||||||
unary []grpc.UnaryServerInterceptor
|
|
||||||
)
|
|
||||||
|
|
||||||
if p.Viper.GetBool("node.grpc.billing") {
|
|
||||||
unary = append(unary, unaryBilling)
|
|
||||||
stream = append(stream, streamBilling)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Viper.GetBool("node.grpc.logging") {
|
|
||||||
stream = append(stream, gZap.StreamServerInterceptor(p.Logger))
|
|
||||||
unary = append(unary, gZap.UnaryServerInterceptor(p.Logger))
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Viper.GetBool("node.grpc.metrics") {
|
|
||||||
stream = append(stream, prometheus.StreamServerInterceptor)
|
|
||||||
unary = append(unary, prometheus.UnaryServerInterceptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add stream options:
|
|
||||||
if len(stream) > 0 {
|
|
||||||
options = append(options,
|
|
||||||
grpc.StreamInterceptor(middleware.ChainStreamServer(stream...)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add unary options:
|
|
||||||
if len(unary) > 0 {
|
|
||||||
options = append(options,
|
|
||||||
grpc.UnaryInterceptor(middleware.ChainUnaryServer(unary...)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
g := grpc.NewServer(options...)
|
|
||||||
|
|
||||||
// Service services here:
|
|
||||||
for _, service := range p.Services {
|
|
||||||
p.Logger.Info("register gRPC service",
|
|
||||||
zap.String("service", service.Name()))
|
|
||||||
service.Register(g)
|
|
||||||
}
|
|
||||||
|
|
||||||
return g
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
package morph
|
|
||||||
|
|
||||||
import (
|
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance"
|
|
||||||
clientWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance/wrapper"
|
|
||||||
accounting "github.com/nspcc-dev/neofs-node/pkg/network/transport/accounting/grpc"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
)
|
|
||||||
|
|
||||||
type balanceContractResult struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
Client *clientWrapper.Wrapper
|
|
||||||
|
|
||||||
AccountingService accounting.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
// BalanceContractName is a name of Balance contract config sub-section.
|
|
||||||
const BalanceContractName = "balance"
|
|
||||||
|
|
||||||
const (
|
|
||||||
balanceContractBalanceOfOpt = "balance_of_method"
|
|
||||||
|
|
||||||
balanceContractDecimalsOfOpt = "decimals_method"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BalanceContractBalanceOfOptPath is a path to balanceOf method name option.
|
|
||||||
func BalanceContractBalanceOfOptPath() string {
|
|
||||||
return optPath(prefix, BalanceContractName, balanceContractBalanceOfOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BalanceContractDecimalsOfOptPath is a path to decimals method name option.
|
|
||||||
func BalanceContractDecimalsOfOptPath() string {
|
|
||||||
return optPath(prefix, BalanceContractName, balanceContractDecimalsOfOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBalanceContract(p contractParams) (res balanceContractResult, err error) {
|
|
||||||
client, ok := p.MorphContracts[BalanceContractName]
|
|
||||||
if !ok {
|
|
||||||
err = errors.Errorf("missing %s contract client", BalanceContractName)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
balanceOfMethod = p.Viper.GetString(BalanceContractBalanceOfOptPath())
|
|
||||||
decimalsMethod = p.Viper.GetString(BalanceContractDecimalsOfOptPath())
|
|
||||||
)
|
|
||||||
|
|
||||||
var c *contract.Client
|
|
||||||
if c, err = contract.New(client,
|
|
||||||
contract.WithBalanceOfMethod(balanceOfMethod),
|
|
||||||
contract.WithDecimalsMethod(decimalsMethod),
|
|
||||||
); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.Client, err = clientWrapper.New(c); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.AccountingService, err = accounting.New(accounting.Params{
|
|
||||||
ContractClient: res.Client,
|
|
||||||
}); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,138 +0,0 @@
|
||||||
package morph
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SmartContracts maps smart contract name to contract client.
|
|
||||||
type SmartContracts map[string]*client.StaticClient
|
|
||||||
|
|
||||||
// EventHandlers maps notification event name to handler information.
|
|
||||||
type EventHandlers map[string]event.HandlerInfo
|
|
||||||
|
|
||||||
type morphContractsParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Viper *viper.Viper
|
|
||||||
|
|
||||||
Client *client.Client
|
|
||||||
|
|
||||||
Listener event.Listener
|
|
||||||
}
|
|
||||||
|
|
||||||
type contractParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Viper *viper.Viper
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
|
|
||||||
MorphContracts SmartContracts
|
|
||||||
|
|
||||||
NodeInfo netmap.Info
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMorphContracts(p morphContractsParams) (SmartContracts, EventHandlers, error) {
|
|
||||||
mContracts := make(map[string]*client.StaticClient, len(ContractNames))
|
|
||||||
mHandlers := make(map[string]event.HandlerInfo)
|
|
||||||
|
|
||||||
for _, contractName := range ContractNames {
|
|
||||||
scHash, err := util.Uint160DecodeStringLE(
|
|
||||||
p.Viper.GetString(
|
|
||||||
ScriptHashOptPath(contractName),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fee := util.Fixed8FromInt64(
|
|
||||||
p.Viper.GetInt64(
|
|
||||||
InvocationFeeOptPath(contractName),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
mContracts[contractName], err = client.NewStatic(p.Client, scHash, fee)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// set event parsers
|
|
||||||
parserInfo := event.ParserInfo{}
|
|
||||||
parserInfo.SetScriptHash(scHash)
|
|
||||||
|
|
||||||
handlerInfo := event.HandlerInfo{}
|
|
||||||
handlerInfo.SetScriptHash(scHash)
|
|
||||||
|
|
||||||
for _, item := range mParsers[contractName] {
|
|
||||||
parserInfo.SetParser(item.parser)
|
|
||||||
|
|
||||||
optPath := ContractEventOptPath(contractName, item.typ)
|
|
||||||
|
|
||||||
typEvent := event.TypeFromString(
|
|
||||||
p.Viper.GetString(optPath),
|
|
||||||
)
|
|
||||||
|
|
||||||
parserInfo.SetType(typEvent)
|
|
||||||
handlerInfo.SetType(typEvent)
|
|
||||||
|
|
||||||
p.Listener.SetParser(parserInfo)
|
|
||||||
|
|
||||||
mHandlers[optPath] = handlerInfo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mContracts, mHandlers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const prefix = "morph"
|
|
||||||
|
|
||||||
const (
|
|
||||||
endpointOpt = "endpoint"
|
|
||||||
|
|
||||||
dialTimeoutOpt = "dial_timeout"
|
|
||||||
|
|
||||||
magicNumberOpt = "magic_number"
|
|
||||||
|
|
||||||
scriptHashOpt = "script_hash"
|
|
||||||
|
|
||||||
invocationFeeOpt = "invocation_fee"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContractNames is a list of smart contract names.
|
|
||||||
var ContractNames = []string{
|
|
||||||
containerContractName,
|
|
||||||
NetmapContractName,
|
|
||||||
BalanceContractName,
|
|
||||||
}
|
|
||||||
|
|
||||||
// EndpointOptPath returns the config path to goclient endpoint.
|
|
||||||
func EndpointOptPath() string {
|
|
||||||
return optPath(prefix, endpointOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MagicNumberOptPath returns the config path to goclient magic number.
|
|
||||||
func MagicNumberOptPath() string {
|
|
||||||
return optPath(prefix, magicNumberOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DialTimeoutOptPath returns the config path to goclient dial timeout.
|
|
||||||
func DialTimeoutOptPath() string {
|
|
||||||
return optPath(prefix, dialTimeoutOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScriptHashOptPath calculates the config path to script hash config of particular contract.
|
|
||||||
func ScriptHashOptPath(name string) string {
|
|
||||||
return optPath(prefix, name, scriptHashOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvocationFeeOptPath calculates the config path to invocation fee config of particular contract.
|
|
||||||
func InvocationFeeOptPath(name string) string {
|
|
||||||
return optPath(prefix, name, invocationFeeOpt)
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
package morph
|
|
||||||
|
|
||||||
import (
|
|
||||||
eacl "github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
|
||||||
clientWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/container/wrapper"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
)
|
|
||||||
|
|
||||||
type containerContractResult struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
ExtendedACLStore eacl.Storage
|
|
||||||
|
|
||||||
ContainerStorage storage.Storage
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
containerContractName = "container"
|
|
||||||
|
|
||||||
containerContractSetEACLOpt = "set_eacl_method"
|
|
||||||
|
|
||||||
containerContractEACLOpt = "get_eacl_method"
|
|
||||||
|
|
||||||
containerContractPutOpt = "put_method"
|
|
||||||
|
|
||||||
containerContractGetOpt = "get_method"
|
|
||||||
|
|
||||||
containerContractDelOpt = "delete_method"
|
|
||||||
|
|
||||||
containerContractListOpt = "list_method"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ContainerContractSetEACLOptPath returns the config path to set eACL method name of Container contract.
|
|
||||||
func ContainerContractSetEACLOptPath() string {
|
|
||||||
return optPath(prefix, containerContractName, containerContractSetEACLOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerContractEACLOptPath returns the config path to get eACL method name of Container contract.
|
|
||||||
func ContainerContractEACLOptPath() string {
|
|
||||||
return optPath(prefix, containerContractName, containerContractEACLOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerContractPutOptPath returns the config path to put container method name of Container contract.
|
|
||||||
func ContainerContractPutOptPath() string {
|
|
||||||
return optPath(prefix, containerContractName, containerContractPutOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerContractGetOptPath returns the config path to get container method name of Container contract.
|
|
||||||
func ContainerContractGetOptPath() string {
|
|
||||||
return optPath(prefix, containerContractName, containerContractGetOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerContractDelOptPath returns the config path to delete container method name of Container contract.
|
|
||||||
func ContainerContractDelOptPath() string {
|
|
||||||
return optPath(prefix, containerContractName, containerContractDelOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerContractListOptPath returns the config path to list containers method name of Container contract.
|
|
||||||
func ContainerContractListOptPath() string {
|
|
||||||
return optPath(prefix, containerContractName, containerContractListOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newContainerContract(p contractParams) (res containerContractResult, err error) {
|
|
||||||
client, ok := p.MorphContracts[containerContractName]
|
|
||||||
if !ok {
|
|
||||||
err = errors.Errorf("missing %s contract client", containerContractName)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
setEACLMethod = p.Viper.GetString(ContainerContractSetEACLOptPath())
|
|
||||||
eaclMethod = p.Viper.GetString(ContainerContractEACLOptPath())
|
|
||||||
getMethod = p.Viper.GetString(ContainerContractGetOptPath())
|
|
||||||
putMethod = p.Viper.GetString(ContainerContractPutOptPath())
|
|
||||||
deleteMethod = p.Viper.GetString(ContainerContractDelOptPath())
|
|
||||||
listMethod = p.Viper.GetString(ContainerContractListOptPath())
|
|
||||||
)
|
|
||||||
|
|
||||||
var containerClient *contract.Client
|
|
||||||
if containerClient, err = contract.New(client,
|
|
||||||
contract.WithSetEACLMethod(setEACLMethod),
|
|
||||||
contract.WithEACLMethod(eaclMethod),
|
|
||||||
contract.WithGetMethod(getMethod),
|
|
||||||
contract.WithPutMethod(putMethod),
|
|
||||||
contract.WithDeleteMethod(deleteMethod),
|
|
||||||
contract.WithListMethod(listMethod),
|
|
||||||
); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var wrapClient *clientWrapper.Wrapper
|
|
||||||
if wrapClient, err = clientWrapper.New(containerClient); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res.ContainerStorage = wrapClient
|
|
||||||
res.ExtendedACLStore = wrapClient
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package morph
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event/netmap"
|
|
||||||
)
|
|
||||||
|
|
||||||
const eventOpt = "event"
|
|
||||||
|
|
||||||
// NewEpochEventType is a config section of new epoch notification event.
|
|
||||||
const NewEpochEventType = "new_epoch"
|
|
||||||
|
|
||||||
// ContractEventOptPath returns the config path to notification event name of particular contract.
|
|
||||||
func ContractEventOptPath(contract, event string) string {
|
|
||||||
return optPath(prefix, contract, eventOpt, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
var mParsers = map[string][]struct {
|
|
||||||
typ string
|
|
||||||
parser event.Parser
|
|
||||||
}{
|
|
||||||
NetmapContractName: {
|
|
||||||
{
|
|
||||||
typ: NewEpochEventType,
|
|
||||||
parser: netmap.ParseNewEpoch,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package morph
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type morphClientParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Viper *viper.Viper
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
|
|
||||||
Key *ecdsa.PrivateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClient(p morphClientParams) (*client.Client, error) {
|
|
||||||
return client.New(
|
|
||||||
p.Key,
|
|
||||||
p.Viper.GetString(optPath(prefix, endpointOpt)),
|
|
||||||
client.WithLogger(p.Logger),
|
|
||||||
client.WithDialTimeout(p.Viper.GetDuration(optPath(prefix, dialTimeoutOpt))),
|
|
||||||
client.WithMagic(netmode.Magic(p.Viper.GetUint32(optPath(prefix, magicNumberOpt)))),
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package morph
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/subscriber"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type eventListenerParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Viper *viper.Viper
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
var listenerPrefix = optPath(prefix, "listener")
|
|
||||||
|
|
||||||
const (
|
|
||||||
listenerEndpointOpt = "endpoint"
|
|
||||||
|
|
||||||
listenerDialTimeoutOpt = "dial_timeout"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ListenerEndpointOptPath returns the config path to event listener's endpoint.
|
|
||||||
func ListenerEndpointOptPath() string {
|
|
||||||
return optPath(listenerPrefix, listenerEndpointOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenerDialTimeoutOptPath returns the config path to event listener's dial timeout.
|
|
||||||
func ListenerDialTimeoutOptPath() string {
|
|
||||||
return optPath(listenerPrefix, listenerDialTimeoutOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEventListener(p eventListenerParams) (event.Listener, error) {
|
|
||||||
sub, err := subscriber.New(context.Background(), &subscriber.Params{
|
|
||||||
Log: p.Logger,
|
|
||||||
Endpoint: p.Viper.GetString(ListenerEndpointOptPath()),
|
|
||||||
DialTimeout: p.Viper.GetDuration(ListenerDialTimeoutOptPath()),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return event.NewListener(event.ListenerParams{
|
|
||||||
Logger: p.Logger,
|
|
||||||
Subscriber: sub,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package morph
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/module"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Module is a Neo:Morph module.
|
|
||||||
var Module = module.Module{
|
|
||||||
{Constructor: newClient},
|
|
||||||
{Constructor: newMorphContracts},
|
|
||||||
{Constructor: newContainerContract},
|
|
||||||
{Constructor: newNetmapContract},
|
|
||||||
{Constructor: newEventListener},
|
|
||||||
{Constructor: newBalanceContract},
|
|
||||||
}
|
|
||||||
|
|
||||||
func optPath(sections ...string) string {
|
|
||||||
return strings.Join(sections, ".")
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
package morph
|
|
||||||
|
|
||||||
import (
|
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
|
||||||
clientWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/bootstrap"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
)
|
|
||||||
|
|
||||||
type netmapContractResult struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
Client *clientWrapper.Wrapper
|
|
||||||
|
|
||||||
NodeRegisterer *bootstrap.Registerer
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// NetmapContractName is a Netmap contract's config section name.
|
|
||||||
NetmapContractName = "netmap"
|
|
||||||
|
|
||||||
netmapContractAddPeerOpt = "add_peer_method"
|
|
||||||
|
|
||||||
netmapContractNewEpochOpt = "new_epoch_method"
|
|
||||||
|
|
||||||
netmapContractNetmapOpt = "netmap_method"
|
|
||||||
|
|
||||||
netmapContractUpdStateOpt = "update_state_method"
|
|
||||||
|
|
||||||
netmapContractIRListOpt = "ir_list_method"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NetmapContractAddPeerOptPath returns the config path to add peer method of Netmap contract.
|
|
||||||
func NetmapContractAddPeerOptPath() string {
|
|
||||||
return optPath(prefix, NetmapContractName, netmapContractAddPeerOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetmapContractNewEpochOptPath returns the config path to new epoch method of Netmap contract.
|
|
||||||
func NetmapContractNewEpochOptPath() string {
|
|
||||||
return optPath(prefix, NetmapContractName, netmapContractNewEpochOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetmapContractNetmapOptPath returns the config path to get netmap method of Netmap contract.
|
|
||||||
func NetmapContractNetmapOptPath() string {
|
|
||||||
return optPath(prefix, NetmapContractName, netmapContractNetmapOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetmapContractUpdateStateOptPath returns the config path to update state method of Netmap contract.
|
|
||||||
func NetmapContractUpdateStateOptPath() string {
|
|
||||||
return optPath(prefix, NetmapContractName, netmapContractUpdStateOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetmapContractIRListOptPath returns the config path to inner ring list method of Netmap contract.
|
|
||||||
func NetmapContractIRListOptPath() string {
|
|
||||||
return optPath(prefix, NetmapContractName, netmapContractIRListOpt)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newNetmapContract(p contractParams) (res netmapContractResult, err error) {
|
|
||||||
client, ok := p.MorphContracts[NetmapContractName]
|
|
||||||
if !ok {
|
|
||||||
err = errors.Errorf("missing %s contract client", NetmapContractName)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
addPeerMethod = p.Viper.GetString(NetmapContractAddPeerOptPath())
|
|
||||||
newEpochMethod = p.Viper.GetString(NetmapContractNewEpochOptPath())
|
|
||||||
netmapMethod = p.Viper.GetString(NetmapContractNetmapOptPath())
|
|
||||||
updStateMethod = p.Viper.GetString(NetmapContractUpdateStateOptPath())
|
|
||||||
irListMethod = p.Viper.GetString(NetmapContractIRListOptPath())
|
|
||||||
)
|
|
||||||
|
|
||||||
var c *contract.Client
|
|
||||||
if c, err = contract.New(client,
|
|
||||||
contract.WithAddPeerMethod(addPeerMethod),
|
|
||||||
contract.WithNewEpochMethod(newEpochMethod),
|
|
||||||
contract.WithNetMapMethod(netmapMethod),
|
|
||||||
contract.WithUpdateStateMethod(updStateMethod),
|
|
||||||
contract.WithInnerRingListMethod(irListMethod),
|
|
||||||
); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.Client, err = clientWrapper.New(c); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.NodeRegisterer, err = bootstrap.New(res.Client, p.NodeInfo); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package network
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/fasthttp/router"
|
|
||||||
svc "github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/bootstrap"
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
handlerParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Healthy svc.HealthyClient
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
healthyState = "NeoFS node is "
|
|
||||||
defaultContentType = "text/plain; charset=utf-8"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newHTTPHandler(p handlerParams) (fasthttp.RequestHandler, error) {
|
|
||||||
r := router.New()
|
|
||||||
r.RedirectTrailingSlash = true
|
|
||||||
|
|
||||||
r.GET("/-/ready/", func(c *fasthttp.RequestCtx) {
|
|
||||||
c.SetStatusCode(fasthttp.StatusOK)
|
|
||||||
c.SetBodyString(healthyState + "ready")
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/-/healthy/", func(c *fasthttp.RequestCtx) {
|
|
||||||
code := fasthttp.StatusOK
|
|
||||||
msg := "healthy"
|
|
||||||
|
|
||||||
err := p.Healthy.Healthy()
|
|
||||||
if err != nil {
|
|
||||||
code = fasthttp.StatusBadRequest
|
|
||||||
msg = "unhealthy: " + err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Response.Reset()
|
|
||||||
c.SetStatusCode(code)
|
|
||||||
c.SetContentType(defaultContentType)
|
|
||||||
c.SetBodyString(healthyState + msg)
|
|
||||||
})
|
|
||||||
|
|
||||||
return r.Handler, nil
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package network
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/module"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/util/profiler"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Module is a network layer module.
|
|
||||||
var Module = module.Module{
|
|
||||||
{Constructor: newMuxer},
|
|
||||||
{Constructor: newPeers},
|
|
||||||
{Constructor: newPlacement},
|
|
||||||
|
|
||||||
// Metrics is prometheus handler
|
|
||||||
{Constructor: profiler.NewMetrics},
|
|
||||||
// Profiler is pprof handler
|
|
||||||
{Constructor: profiler.NewProfiler},
|
|
||||||
{Constructor: newHTTPHandler},
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package network
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/muxer"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type muxerParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
P2P *grpc.Server
|
|
||||||
|
|
||||||
Address multiaddr.Multiaddr
|
|
||||||
ShutdownTTL time.Duration `name:"shutdown_ttl"`
|
|
||||||
API fasthttp.RequestHandler
|
|
||||||
Viper *viper.Viper
|
|
||||||
}
|
|
||||||
|
|
||||||
const appName = "neofs-node"
|
|
||||||
|
|
||||||
func newFastHTTPServer(p muxerParams) *fasthttp.Server {
|
|
||||||
srv := new(fasthttp.Server)
|
|
||||||
srv.Name = appName
|
|
||||||
srv.ReadBufferSize = p.Viper.GetInt("muxer.http.read_buffer_size")
|
|
||||||
srv.WriteBufferSize = p.Viper.GetInt("muxer.http.write_buffer_size")
|
|
||||||
srv.ReadTimeout = p.Viper.GetDuration("muxer.http.read_timeout")
|
|
||||||
srv.WriteTimeout = p.Viper.GetDuration("muxer.http.write_timeout")
|
|
||||||
srv.GetOnly = true
|
|
||||||
srv.DisableHeaderNamesNormalizing = true
|
|
||||||
srv.NoDefaultServerHeader = true
|
|
||||||
srv.NoDefaultContentType = true
|
|
||||||
srv.Handler = p.API
|
|
||||||
|
|
||||||
return srv
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMuxer(p muxerParams) muxer.Mux {
|
|
||||||
return muxer.New(muxer.Params{
|
|
||||||
P2P: p.P2P,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Address: p.Address,
|
|
||||||
ShutdownTTL: p.ShutdownTTL,
|
|
||||||
API: newFastHTTPServer(p),
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package network
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/peers"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type peersParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Viper *viper.Viper
|
|
||||||
Logger *zap.Logger
|
|
||||||
Address multiaddr.Multiaddr
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPeers(p peersParams) (peers.Interface, error) {
|
|
||||||
return peers.New(peers.Params{
|
|
||||||
Logger: p.Logger,
|
|
||||||
ConnectionTTL: p.Viper.GetDuration("peers.connections_ttl"),
|
|
||||||
ConnectionIDLE: p.Viper.GetDuration("peers.connections_idle"),
|
|
||||||
MetricsTimeout: p.Viper.GetDuration("peers.metrics_timeout"),
|
|
||||||
KeepAliveTTL: p.Viper.GetDuration("peers.keep_alive.ttl"),
|
|
||||||
KeepAlivePingTTL: p.Viper.GetDuration("peers.keep_alive.ping"),
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package network
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/morph"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
|
||||||
netmapevent "github.com/nspcc-dev/neofs-node/pkg/morph/event/netmap"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/peers"
|
|
||||||
state "github.com/nspcc-dev/neofs-node/pkg/network/transport/state/grpc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
placementParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Log *zap.Logger
|
|
||||||
Peers peers.Store
|
|
||||||
Fetcher storage.Storage
|
|
||||||
|
|
||||||
MorphEventListener event.Listener
|
|
||||||
|
|
||||||
NetMapClient *contract.Wrapper
|
|
||||||
|
|
||||||
MorphEventHandlers morph.EventHandlers
|
|
||||||
}
|
|
||||||
|
|
||||||
placementOutput struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
Placement placement.Component
|
|
||||||
Healthy state.HealthChecker `group:"healthy"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const defaultChronologyDuraion = 2
|
|
||||||
|
|
||||||
func newPlacement(p placementParams) placementOutput {
|
|
||||||
place := placement.New(placement.Params{
|
|
||||||
Log: p.Log,
|
|
||||||
Peerstore: p.Peers,
|
|
||||||
Fetcher: p.Fetcher,
|
|
||||||
ChronologyDuration: defaultChronologyDuraion,
|
|
||||||
})
|
|
||||||
|
|
||||||
if handlerInfo, ok := p.MorphEventHandlers[morph.ContractEventOptPath(
|
|
||||||
morph.NetmapContractName,
|
|
||||||
morph.NewEpochEventType,
|
|
||||||
)]; ok {
|
|
||||||
handlerInfo.SetHandler(func(ev event.Event) {
|
|
||||||
nm, err := p.NetMapClient.GetNetMap()
|
|
||||||
if err != nil {
|
|
||||||
p.Log.Error("could not get network map",
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := place.Update(
|
|
||||||
ev.(netmapevent.NewEpoch).EpochNumber(),
|
|
||||||
nm,
|
|
||||||
); err != nil {
|
|
||||||
p.Log.Error("could not update network map in placement component",
|
|
||||||
zap.String("error", err.Error()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
p.MorphEventListener.RegisterHandler(handlerInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
return placementOutput{
|
|
||||||
Placement: place,
|
|
||||||
Healthy: place.(state.HealthChecker),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/session"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/peers"
|
|
||||||
object "github.com/nspcc-dev/neofs-node/pkg/network/transport/object/grpc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/replication/storage"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transport"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
cnrHandlerParams struct {
|
|
||||||
*viper.Viper
|
|
||||||
*zap.Logger
|
|
||||||
Placer *placement.PlacementWrapper
|
|
||||||
PeerStore peers.Store
|
|
||||||
Peers peers.Interface
|
|
||||||
TimeoutsPrefix string
|
|
||||||
Key *ecdsa.PrivateKey
|
|
||||||
|
|
||||||
TokenStore session.PrivateTokenStore
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func newObjectsContainerHandler(p cnrHandlerParams) (transport.SelectiveContainerExecutor, error) {
|
|
||||||
as, err := storage.NewAddressStore(p.PeerStore, p.Logger)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
multiTransport, err := object.NewMultiTransport(object.MultiTransportParams{
|
|
||||||
AddressStore: as,
|
|
||||||
EpochReceiver: p.Placer,
|
|
||||||
RemoteService: object.NewRemoteService(p.Peers),
|
|
||||||
Logger: p.Logger,
|
|
||||||
Key: p.Key,
|
|
||||||
PutTimeout: p.Viper.GetDuration(p.TimeoutsPrefix + ".timeouts.put"),
|
|
||||||
GetTimeout: p.Viper.GetDuration(p.TimeoutsPrefix + ".timeouts.get"),
|
|
||||||
HeadTimeout: p.Viper.GetDuration(p.TimeoutsPrefix + ".timeouts.head"),
|
|
||||||
SearchTimeout: p.Viper.GetDuration(p.TimeoutsPrefix + ".timeouts.search"),
|
|
||||||
RangeHashTimeout: p.Viper.GetDuration(p.TimeoutsPrefix + ".timeouts.range_hash"),
|
|
||||||
DialTimeout: p.Viper.GetDuration("object.dial_timeout"),
|
|
||||||
|
|
||||||
PrivateTokenStore: p.TokenStore,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
exec, err := transport.NewContainerTraverseExecutor(multiTransport)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return transport.NewObjectContainerHandler(transport.ObjectContainerHandlerParams{
|
|
||||||
NodeLister: p.Placer,
|
|
||||||
Executor: exec,
|
|
||||||
Logger: p.Logger,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
svc "github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/bootstrap"
|
|
||||||
eacl "github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
|
||||||
container "github.com/nspcc-dev/neofs-node/pkg/network/transport/container/grpc"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type cnrParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
|
|
||||||
Healthy svc.HealthyClient
|
|
||||||
|
|
||||||
ExtendedACLStore eacl.Storage
|
|
||||||
|
|
||||||
ContainerStorage storage.Storage
|
|
||||||
}
|
|
||||||
|
|
||||||
func newContainerService(p cnrParams) (container.Service, error) {
|
|
||||||
return container.New(container.Params{
|
|
||||||
Logger: p.Logger,
|
|
||||||
Healthy: p.Healthy,
|
|
||||||
Store: p.ContainerStorage,
|
|
||||||
ExtendedACLStore: p.ExtendedACLStore,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/bucket"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/bucket/boltdb"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/bucket/fsbucket"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Buckets map[string]bucket.Bucket
|
|
||||||
|
|
||||||
const (
|
|
||||||
fsBucket = "fsbucket"
|
|
||||||
boltBucket = "bolt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newBuckets(v *viper.Viper) (Buckets, error) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
mBuckets = make(Buckets)
|
|
||||||
)
|
|
||||||
|
|
||||||
if mBuckets[fsBucket], err = fsbucket.NewBucket(v); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
boltOpts, err := boltdb.NewOptions(v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if mBuckets[boltBucket], err = boltdb.NewBucket(&boltOpts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mBuckets, nil
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/localstore"
|
|
||||||
meta2 "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/meta"
|
|
||||||
metrics2 "github.com/nspcc-dev/neofs-node/pkg/services/metrics"
|
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
localstoreParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
Buckets Buckets
|
|
||||||
Counter *atomic.Float64
|
|
||||||
Collector metrics2.Collector
|
|
||||||
}
|
|
||||||
|
|
||||||
metaIterator struct {
|
|
||||||
iter localstore.Iterator
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func newMetaIterator(iter localstore.Iterator) meta2.Iterator {
|
|
||||||
return &metaIterator{iter: iter}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *metaIterator) Iterate(handler meta2.IterateFunc) error {
|
|
||||||
return m.iter.Iterate(nil, func(objMeta *localstore.ObjectMeta) bool {
|
|
||||||
return handler == nil || handler(objMeta.Object) != nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func newLocalstore(p localstoreParams) (localstore.Localstore, error) {
|
|
||||||
local, err := localstore.New(localstore.Params{
|
|
||||||
BlobBucket: p.Buckets[fsBucket],
|
|
||||||
MetaBucket: p.Buckets[boltBucket],
|
|
||||||
Logger: p.Logger,
|
|
||||||
Collector: p.Collector,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
iter := newMetaIterator(local)
|
|
||||||
p.Collector.SetCounter(local)
|
|
||||||
p.Collector.SetIterator(iter)
|
|
||||||
|
|
||||||
return local, nil
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
metrics "github.com/nspcc-dev/neofs-node/pkg/network/transport/metrics/grpc"
|
|
||||||
metrics2 "github.com/nspcc-dev/neofs-node/pkg/services/metrics"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/atomic"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
metricsParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
Options []string `name:"node_options"`
|
|
||||||
Viper *viper.Viper
|
|
||||||
Buckets Buckets
|
|
||||||
}
|
|
||||||
|
|
||||||
metricsServiceParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
Collector metrics2.Collector
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func newObjectCounter() *atomic.Float64 { return atomic.NewFloat64(0) }
|
|
||||||
|
|
||||||
func newMetricsService(p metricsServiceParams) (metrics.Service, error) {
|
|
||||||
return metrics.New(metrics.Params{
|
|
||||||
Logger: p.Logger,
|
|
||||||
Collector: p.Collector,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMetricsCollector(p metricsParams) (metrics2.Collector, error) {
|
|
||||||
return metrics2.New(metrics2.Params{
|
|
||||||
Options: p.Options,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Interval: p.Viper.GetDuration("metrics_collector.interval"),
|
|
||||||
MetricsStore: p.Buckets[fsBucket],
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/session"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/bootstrap"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/module"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/worker"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/grpc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/morph"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/network"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/settings"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/workers"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
|
||||||
libboot "github.com/nspcc-dev/neofs-node/pkg/network/bootstrap"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/peers"
|
|
||||||
metrics2 "github.com/nspcc-dev/neofs-node/pkg/services/metrics"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/replication"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type jobParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
Viper *viper.Viper
|
|
||||||
Peers peers.Store
|
|
||||||
|
|
||||||
Replicator replication.Manager
|
|
||||||
PeersInterface peers.Interface
|
|
||||||
Metrics metrics2.Collector
|
|
||||||
|
|
||||||
MorphEventListener event.Listener
|
|
||||||
|
|
||||||
NodeRegisterer *libboot.Registerer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module is a NeoFS node module.
|
|
||||||
var Module = module.Module{
|
|
||||||
{Constructor: attachJobs},
|
|
||||||
{Constructor: newPeerstore},
|
|
||||||
{Constructor: attachServices},
|
|
||||||
{Constructor: newBuckets},
|
|
||||||
{Constructor: newMetricsCollector},
|
|
||||||
{Constructor: newObjectCounter},
|
|
||||||
|
|
||||||
// -- Container gRPC handlers -- //
|
|
||||||
{Constructor: newContainerService},
|
|
||||||
|
|
||||||
// -- gRPC Services -- //
|
|
||||||
|
|
||||||
// -- Local store -- //
|
|
||||||
{Constructor: newLocalstore},
|
|
||||||
|
|
||||||
// -- Object manager -- //
|
|
||||||
{Constructor: newObjectManager},
|
|
||||||
|
|
||||||
// -- Replication manager -- //
|
|
||||||
{Constructor: newReplicationManager},
|
|
||||||
|
|
||||||
// -- Session service -- //
|
|
||||||
{Constructor: session.NewMapTokenStore},
|
|
||||||
{Constructor: newSessionService},
|
|
||||||
|
|
||||||
// -- Placement tool -- //
|
|
||||||
{Constructor: newPlacementTool},
|
|
||||||
|
|
||||||
// metrics service -- //
|
|
||||||
{Constructor: newMetricsService},
|
|
||||||
}.Append(
|
|
||||||
// app specific modules:
|
|
||||||
grpc.Module,
|
|
||||||
network.Module,
|
|
||||||
workers.Module,
|
|
||||||
settings.Module,
|
|
||||||
bootstrap.Module,
|
|
||||||
morph.Module,
|
|
||||||
)
|
|
||||||
|
|
||||||
func attachJobs(p jobParams) worker.Jobs {
|
|
||||||
return worker.Jobs{
|
|
||||||
"peers": p.PeersInterface.Job,
|
|
||||||
"metrics": p.Metrics.Start,
|
|
||||||
"event_listener": p.MorphEventListener.Listen,
|
|
||||||
"replicator": p.Replicator.Process,
|
|
||||||
"boot": p.NodeRegisterer.Bootstrap,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,201 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/bootstrap"
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/hash"
|
|
||||||
apiobj "github.com/nspcc-dev/neofs-api-go/object"
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/session"
|
|
||||||
eacl "github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/localstore"
|
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/peers"
|
|
||||||
object "github.com/nspcc-dev/neofs-node/pkg/network/transport/object/grpc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
|
||||||
storage2 "github.com/nspcc-dev/neofs-node/pkg/services/object_manager/replication/storage"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transformer"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transport"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transport/storagegroup"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
objectManagerParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
Viper *viper.Viper
|
|
||||||
LocalStore localstore.Localstore
|
|
||||||
|
|
||||||
PeersInterface peers.Interface
|
|
||||||
|
|
||||||
Peers peers.Store
|
|
||||||
Placement placement.Component
|
|
||||||
TokenStore session.PrivateTokenStore
|
|
||||||
Options []string `name:"node_options"`
|
|
||||||
Key *ecdsa.PrivateKey
|
|
||||||
|
|
||||||
NetMapClient *contract.Wrapper
|
|
||||||
|
|
||||||
Placer *placement.PlacementWrapper
|
|
||||||
|
|
||||||
ExtendedACLStore eacl.Storage
|
|
||||||
|
|
||||||
ContainerStorage storage.Storage
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
transformersSectionPath = "object.transformers."
|
|
||||||
)
|
|
||||||
|
|
||||||
const xorSalitor = "xor"
|
|
||||||
|
|
||||||
func newObjectManager(p objectManagerParams) (object.Service, error) {
|
|
||||||
var sltr object.Salitor
|
|
||||||
|
|
||||||
if p.Viper.GetString("object.salitor") == xorSalitor {
|
|
||||||
sltr = hash.SaltXOR
|
|
||||||
}
|
|
||||||
|
|
||||||
as, err := storage2.NewAddressStore(p.Peers, p.Logger)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rs := object.NewRemoteService(p.PeersInterface)
|
|
||||||
|
|
||||||
pto := p.Viper.GetDuration("object.put.timeout")
|
|
||||||
gto := p.Viper.GetDuration("object.get.timeout")
|
|
||||||
hto := p.Viper.GetDuration("object.head.timeout")
|
|
||||||
sto := p.Viper.GetDuration("object.search.timeout")
|
|
||||||
rhto := p.Viper.GetDuration("object.range_hash.timeout")
|
|
||||||
dto := p.Viper.GetDuration("object.dial_timeout")
|
|
||||||
|
|
||||||
tr, err := object.NewMultiTransport(object.MultiTransportParams{
|
|
||||||
AddressStore: as,
|
|
||||||
EpochReceiver: p.Placer,
|
|
||||||
RemoteService: rs,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Key: p.Key,
|
|
||||||
PutTimeout: pto,
|
|
||||||
GetTimeout: gto,
|
|
||||||
HeadTimeout: hto,
|
|
||||||
SearchTimeout: sto,
|
|
||||||
RangeHashTimeout: rhto,
|
|
||||||
DialTimeout: dto,
|
|
||||||
|
|
||||||
PrivateTokenStore: p.TokenStore,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
exec, err := transport.NewContainerTraverseExecutor(tr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
selectiveExec, err := transport.NewObjectContainerHandler(transport.ObjectContainerHandlerParams{
|
|
||||||
NodeLister: p.Placer,
|
|
||||||
Executor: exec,
|
|
||||||
Logger: p.Logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sgInfoRecv, err := storagegroup.NewStorageGroupInfoReceiver(storagegroup.StorageGroupInfoReceiverParams{
|
|
||||||
SelectiveContainerExecutor: selectiveExec,
|
|
||||||
Logger: p.Logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
verifier, err := storage2.NewLocalIntegrityVerifier()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
trans, err := transformer.NewTransformer(transformer.Params{
|
|
||||||
SGInfoReceiver: sgInfoRecv,
|
|
||||||
EpochReceiver: p.Placer,
|
|
||||||
SizeLimit: uint64(p.Viper.GetInt64(transformersSectionPath+"payload_limiter.max_payload_size") * apiobj.UnitsKB),
|
|
||||||
Verifier: verifier,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
verifier, err = storage2.NewLocalHeadIntegrityVerifier()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return object.New(&object.Params{
|
|
||||||
Verifier: verifier,
|
|
||||||
Salitor: sltr,
|
|
||||||
LocalStore: p.LocalStore,
|
|
||||||
MaxProcessingSize: p.Viper.GetUint64("object.max_processing_size") * uint64(apiobj.UnitsMB),
|
|
||||||
StorageCapacity: bootstrap.NodeInfo{Options: p.Options}.Capacity() * uint64(apiobj.UnitsGB),
|
|
||||||
PoolSize: p.Viper.GetInt("object.workers_count"),
|
|
||||||
Placer: p.Placer,
|
|
||||||
Transformer: trans,
|
|
||||||
ObjectRestorer: transformer.NewRestorePipeline(
|
|
||||||
transformer.SplitRestorer(),
|
|
||||||
),
|
|
||||||
RemoteService: rs,
|
|
||||||
AddressStore: as,
|
|
||||||
Logger: p.Logger,
|
|
||||||
TokenStore: p.TokenStore,
|
|
||||||
EpochReceiver: p.Placer,
|
|
||||||
PlacementWrapper: p.Placer,
|
|
||||||
Key: p.Key,
|
|
||||||
CheckACL: p.Viper.GetBool("object.check_acl"),
|
|
||||||
DialTimeout: p.Viper.GetDuration("object.dial_timeout"),
|
|
||||||
MaxPayloadSize: p.Viper.GetUint64("object.transformers.payload_limiter.max_payload_size") * uint64(apiobj.UnitsKB),
|
|
||||||
PutParams: object.OperationParams{
|
|
||||||
Timeout: pto,
|
|
||||||
LogErrors: p.Viper.GetBool("object.put.log_errs"),
|
|
||||||
},
|
|
||||||
GetParams: object.OperationParams{
|
|
||||||
Timeout: gto,
|
|
||||||
LogErrors: p.Viper.GetBool("object.get.log_errs"),
|
|
||||||
},
|
|
||||||
HeadParams: object.OperationParams{
|
|
||||||
Timeout: hto,
|
|
||||||
LogErrors: p.Viper.GetBool("object.head.log_errs"),
|
|
||||||
},
|
|
||||||
DeleteParams: object.OperationParams{
|
|
||||||
Timeout: p.Viper.GetDuration("object.delete.timeout"),
|
|
||||||
LogErrors: p.Viper.GetBool("object.get.log_errs"),
|
|
||||||
},
|
|
||||||
SearchParams: object.OperationParams{
|
|
||||||
Timeout: sto,
|
|
||||||
LogErrors: p.Viper.GetBool("object.search.log_errs"),
|
|
||||||
},
|
|
||||||
RangeParams: object.OperationParams{
|
|
||||||
Timeout: p.Viper.GetDuration("object.range.timeout"),
|
|
||||||
LogErrors: p.Viper.GetBool("object.range.log_errs"),
|
|
||||||
},
|
|
||||||
RangeHashParams: object.OperationParams{
|
|
||||||
Timeout: rhto,
|
|
||||||
LogErrors: p.Viper.GetBool("object.range_hash.log_errs"),
|
|
||||||
},
|
|
||||||
Assembly: p.Viper.GetBool("object.assembly"),
|
|
||||||
|
|
||||||
WindowSize: p.Viper.GetInt("object.window_size"),
|
|
||||||
|
|
||||||
ContainerStorage: p.ContainerStorage,
|
|
||||||
NetmapClient: p.NetMapClient,
|
|
||||||
|
|
||||||
SGInfoReceiver: sgInfoRecv,
|
|
||||||
|
|
||||||
ExtendedACLSource: p.ExtendedACLStore,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/peers"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type peerstoreParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
PrivateKey *ecdsa.PrivateKey
|
|
||||||
Address multiaddr.Multiaddr
|
|
||||||
Store peers.Storage `optional:"true"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPeerstore(p peerstoreParams) (peers.Store, error) {
|
|
||||||
return peers.NewStore(peers.StoreParams{
|
|
||||||
Storage: p.Store,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Addr: p.Address,
|
|
||||||
Key: p.PrivateKey,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
placementToolParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Placement placement.Component
|
|
||||||
}
|
|
||||||
|
|
||||||
placementToolResult struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
Placer *placement.PlacementWrapper
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func newPlacementTool(p placementToolParams) (res placementToolResult, err error) {
|
|
||||||
if res.Placer, err = placement.NewObjectPlacer(p.Placement); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,385 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/hash"
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/session"
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/morph"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/localstore"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/event/netmap"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/peers"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/replication"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/replication/storage"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
replicationManagerParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Viper *viper.Viper
|
|
||||||
|
|
||||||
PeersInterface peers.Interface
|
|
||||||
|
|
||||||
LocalStore localstore.Localstore
|
|
||||||
Peers peers.Store
|
|
||||||
Placement placement.Component
|
|
||||||
Logger *zap.Logger
|
|
||||||
Key *ecdsa.PrivateKey
|
|
||||||
|
|
||||||
Placer *placement.PlacementWrapper
|
|
||||||
|
|
||||||
TokenStore session.PrivateTokenStore
|
|
||||||
|
|
||||||
MorphEventListener event.Listener
|
|
||||||
MorphEventHandlers morph.EventHandlers
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
mainReplicationPrefix = "replication"
|
|
||||||
managerPrefix = "manager"
|
|
||||||
placementHonorerPrefix = "placement_honorer"
|
|
||||||
locationDetectorPrefix = "location_detector"
|
|
||||||
storageValidatorPrefix = "storage_validator"
|
|
||||||
replicatorPrefix = "replicator"
|
|
||||||
restorerPrefix = "restorer"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newReplicationManager(p replicationManagerParams) (replication.Manager, error) {
|
|
||||||
as, err := storage.NewAddressStore(p.Peers, p.Logger)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ms, err := replication.NewMultiSolver(replication.MultiSolverParams{
|
|
||||||
AddressStore: as,
|
|
||||||
Placement: p.Placement,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
op := replication.NewObjectPool()
|
|
||||||
|
|
||||||
schd, err := replication.NewReplicationScheduler(replication.SchedulerParams{
|
|
||||||
ContainerActualityChecker: ms,
|
|
||||||
Iterator: p.LocalStore,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
integrityVerifier, err := storage.NewLocalIntegrityVerifier()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
verifier, err := storage.NewObjectValidator(&storage.ObjectValidatorParams{
|
|
||||||
AddressStore: ms,
|
|
||||||
Localstore: p.LocalStore,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Verifier: integrityVerifier,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
placementHonorer, err := newPlacementHonorer(p, ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
locationDetector, err := newLocationDetector(p, ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
storageValidator, err := newStorageValidator(p, ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
replicator, err := newObjectReplicator(p, ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
restorer, err := newRestorer(p, ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix := mainReplicationPrefix + "." + managerPrefix + "."
|
|
||||||
capPrefix := prefix + "capacities."
|
|
||||||
|
|
||||||
mngr, err := replication.NewManager(replication.ManagerParams{
|
|
||||||
Interval: p.Viper.GetDuration(prefix + "read_pool_interval"),
|
|
||||||
PushTaskTimeout: p.Viper.GetDuration(prefix + "push_task_timeout"),
|
|
||||||
InitPoolSize: p.Viper.GetInt(prefix + "pool_size"),
|
|
||||||
ExpansionRate: p.Viper.GetFloat64(prefix + "pool_expansion_rate"),
|
|
||||||
PlacementHonorerEnabled: p.Viper.GetBool(prefix + "placement_honorer_enabled"),
|
|
||||||
ReplicateTaskChanCap: p.Viper.GetInt(capPrefix + "replicate"),
|
|
||||||
RestoreTaskChanCap: p.Viper.GetInt(capPrefix + "restore"),
|
|
||||||
GarbageChanCap: p.Viper.GetInt(capPrefix + "garbage"),
|
|
||||||
ObjectPool: op,
|
|
||||||
ObjectVerifier: verifier,
|
|
||||||
PlacementHonorer: placementHonorer,
|
|
||||||
ObjectLocationDetector: locationDetector,
|
|
||||||
StorageValidator: storageValidator,
|
|
||||||
ObjectReplicator: replicator,
|
|
||||||
ObjectRestorer: restorer,
|
|
||||||
Scheduler: schd,
|
|
||||||
Logger: p.Logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if handlerInfo, ok := p.MorphEventHandlers[morph.ContractEventOptPath(
|
|
||||||
morph.NetmapContractName,
|
|
||||||
morph.NewEpochEventType,
|
|
||||||
)]; ok {
|
|
||||||
handlerInfo.SetHandler(func(ev event.Event) {
|
|
||||||
mngr.HandleEpoch(
|
|
||||||
context.Background(),
|
|
||||||
ev.(netmap.NewEpoch).EpochNumber(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
p.MorphEventListener.RegisterHandler(handlerInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mngr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPlacementHonorer(p replicationManagerParams, rss replication.RemoteStorageSelector) (replication.PlacementHonorer, error) {
|
|
||||||
prefix := mainReplicationPrefix + "." + placementHonorerPrefix
|
|
||||||
|
|
||||||
och, err := newObjectsContainerHandler(cnrHandlerParams{
|
|
||||||
Viper: p.Viper,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Placer: p.Placer,
|
|
||||||
PeerStore: p.Peers,
|
|
||||||
Peers: p.PeersInterface,
|
|
||||||
TimeoutsPrefix: prefix,
|
|
||||||
Key: p.Key,
|
|
||||||
|
|
||||||
TokenStore: p.TokenStore,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
storage, err := storage.NewObjectStorage(storage.ObjectStorageParams{
|
|
||||||
Localstore: p.LocalStore,
|
|
||||||
SelectiveContainerExecutor: och,
|
|
||||||
Logger: p.Logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return replication.NewPlacementHonorer(replication.PlacementHonorerParams{
|
|
||||||
ObjectSource: storage,
|
|
||||||
ObjectReceptacle: storage,
|
|
||||||
RemoteStorageSelector: rss,
|
|
||||||
PresenceChecker: p.LocalStore,
|
|
||||||
Logger: p.Logger,
|
|
||||||
TaskChanCap: p.Viper.GetInt(prefix + ".chan_capacity"),
|
|
||||||
ResultTimeout: p.Viper.GetDuration(prefix + ".result_timeout"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func newLocationDetector(p replicationManagerParams, ms replication.MultiSolver) (replication.ObjectLocationDetector, error) {
|
|
||||||
prefix := mainReplicationPrefix + "." + locationDetectorPrefix
|
|
||||||
|
|
||||||
och, err := newObjectsContainerHandler(cnrHandlerParams{
|
|
||||||
Viper: p.Viper,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Placer: p.Placer,
|
|
||||||
PeerStore: p.Peers,
|
|
||||||
Peers: p.PeersInterface,
|
|
||||||
TimeoutsPrefix: prefix,
|
|
||||||
Key: p.Key,
|
|
||||||
|
|
||||||
TokenStore: p.TokenStore,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
locator, err := storage.NewObjectLocator(storage.LocatorParams{
|
|
||||||
SelectiveContainerExecutor: och,
|
|
||||||
Logger: p.Logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return replication.NewLocationDetector(&replication.LocationDetectorParams{
|
|
||||||
WeightComparator: ms,
|
|
||||||
ObjectLocator: locator,
|
|
||||||
ReservationRatioReceiver: ms,
|
|
||||||
PresenceChecker: p.LocalStore,
|
|
||||||
Logger: p.Logger,
|
|
||||||
TaskChanCap: p.Viper.GetInt(prefix + ".chan_capacity"),
|
|
||||||
ResultTimeout: p.Viper.GetDuration(prefix + ".result_timeout"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStorageValidator(p replicationManagerParams, as replication.AddressStore) (replication.StorageValidator, error) {
|
|
||||||
prefix := mainReplicationPrefix + "." + storageValidatorPrefix
|
|
||||||
|
|
||||||
var sltr storage.Salitor
|
|
||||||
|
|
||||||
switch v := p.Viper.GetString(prefix + ".salitor"); v {
|
|
||||||
case xorSalitor:
|
|
||||||
sltr = hash.SaltXOR
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("unsupported salitor: %s", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
och, err := newObjectsContainerHandler(cnrHandlerParams{
|
|
||||||
Viper: p.Viper,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Placer: p.Placer,
|
|
||||||
PeerStore: p.Peers,
|
|
||||||
Peers: p.PeersInterface,
|
|
||||||
TimeoutsPrefix: prefix,
|
|
||||||
Key: p.Key,
|
|
||||||
|
|
||||||
TokenStore: p.TokenStore,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
headVerifier, err := storage.NewLocalHeadIntegrityVerifier()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
verifier, err := storage.NewObjectValidator(&storage.ObjectValidatorParams{
|
|
||||||
AddressStore: as,
|
|
||||||
Localstore: p.LocalStore,
|
|
||||||
SelectiveContainerExecutor: och,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Salitor: sltr,
|
|
||||||
SaltSize: p.Viper.GetInt(prefix + ".salt_size"),
|
|
||||||
MaxPayloadRangeSize: p.Viper.GetUint64(prefix + ".max_payload_range_size"),
|
|
||||||
PayloadRangeCount: p.Viper.GetInt(prefix + ".payload_range_count"),
|
|
||||||
Verifier: headVerifier,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return replication.NewStorageValidator(replication.StorageValidatorParams{
|
|
||||||
ObjectVerifier: verifier,
|
|
||||||
PresenceChecker: p.LocalStore,
|
|
||||||
Logger: p.Logger,
|
|
||||||
TaskChanCap: p.Viper.GetInt(prefix + ".chan_capacity"),
|
|
||||||
ResultTimeout: p.Viper.GetDuration(prefix + ".result_timeout"),
|
|
||||||
AddrStore: as,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func newObjectReplicator(p replicationManagerParams, rss replication.RemoteStorageSelector) (replication.ObjectReplicator, error) {
|
|
||||||
prefix := mainReplicationPrefix + "." + replicatorPrefix
|
|
||||||
|
|
||||||
och, err := newObjectsContainerHandler(cnrHandlerParams{
|
|
||||||
Viper: p.Viper,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Placer: p.Placer,
|
|
||||||
PeerStore: p.Peers,
|
|
||||||
Peers: p.PeersInterface,
|
|
||||||
TimeoutsPrefix: prefix,
|
|
||||||
Key: p.Key,
|
|
||||||
|
|
||||||
TokenStore: p.TokenStore,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
storage, err := storage.NewObjectStorage(storage.ObjectStorageParams{
|
|
||||||
Localstore: p.LocalStore,
|
|
||||||
SelectiveContainerExecutor: och,
|
|
||||||
Logger: p.Logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return replication.NewReplicator(replication.ObjectReplicatorParams{
|
|
||||||
RemoteStorageSelector: rss,
|
|
||||||
ObjectSource: storage,
|
|
||||||
ObjectReceptacle: storage,
|
|
||||||
PresenceChecker: p.LocalStore,
|
|
||||||
Logger: p.Logger,
|
|
||||||
TaskChanCap: p.Viper.GetInt(prefix + ".chan_capacity"),
|
|
||||||
ResultTimeout: p.Viper.GetDuration(prefix + ".result_timeout"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRestorer(p replicationManagerParams, ms replication.MultiSolver) (replication.ObjectRestorer, error) {
|
|
||||||
prefix := mainReplicationPrefix + "." + restorerPrefix
|
|
||||||
|
|
||||||
och, err := newObjectsContainerHandler(cnrHandlerParams{
|
|
||||||
Viper: p.Viper,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Placer: p.Placer,
|
|
||||||
PeerStore: p.Peers,
|
|
||||||
Peers: p.PeersInterface,
|
|
||||||
TimeoutsPrefix: prefix,
|
|
||||||
Key: p.Key,
|
|
||||||
|
|
||||||
TokenStore: p.TokenStore,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
integrityVerifier, err := storage.NewLocalIntegrityVerifier()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
verifier, err := storage.NewObjectValidator(&storage.ObjectValidatorParams{
|
|
||||||
AddressStore: ms,
|
|
||||||
Localstore: p.LocalStore,
|
|
||||||
SelectiveContainerExecutor: och,
|
|
||||||
Logger: p.Logger,
|
|
||||||
Verifier: integrityVerifier,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
storage, err := storage.NewObjectStorage(storage.ObjectStorageParams{
|
|
||||||
Localstore: p.LocalStore,
|
|
||||||
Logger: p.Logger,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return replication.NewObjectRestorer(&replication.ObjectRestorerParams{
|
|
||||||
ObjectVerifier: verifier,
|
|
||||||
ObjectReceptacle: storage,
|
|
||||||
EpochReceiver: ms,
|
|
||||||
RemoteStorageSelector: ms,
|
|
||||||
PresenceChecker: p.LocalStore,
|
|
||||||
Logger: p.Logger,
|
|
||||||
TaskChanCap: p.Viper.GetInt(prefix + ".chan_capacity"),
|
|
||||||
ResultTimeout: p.Viper.GetDuration(prefix + ".result_timeout"),
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/grpc"
|
|
||||||
accounting "github.com/nspcc-dev/neofs-node/pkg/network/transport/accounting/grpc"
|
|
||||||
container "github.com/nspcc-dev/neofs-node/pkg/network/transport/container/grpc"
|
|
||||||
metrics "github.com/nspcc-dev/neofs-node/pkg/network/transport/metrics/grpc"
|
|
||||||
object "github.com/nspcc-dev/neofs-node/pkg/network/transport/object/grpc"
|
|
||||||
session "github.com/nspcc-dev/neofs-node/pkg/network/transport/session/grpc"
|
|
||||||
state "github.com/nspcc-dev/neofs-node/pkg/network/transport/state/grpc"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
)
|
|
||||||
|
|
||||||
type servicesParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Status state.Service
|
|
||||||
Container container.Service
|
|
||||||
Object object.Service
|
|
||||||
Session session.Service
|
|
||||||
Accounting accounting.Service
|
|
||||||
Metrics metrics.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func attachServices(p servicesParams) grpc.ServicesResult {
|
|
||||||
return grpc.ServicesResult{
|
|
||||||
Services: []grpc.Service{
|
|
||||||
p.Status,
|
|
||||||
p.Container,
|
|
||||||
p.Accounting,
|
|
||||||
p.Metrics,
|
|
||||||
p.Session,
|
|
||||||
p.Object,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
session "github.com/nspcc-dev/neofs-node/pkg/network/transport/session/grpc"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type sessionParams struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Logger *zap.Logger
|
|
||||||
|
|
||||||
TokenStore session.TokenStore
|
|
||||||
|
|
||||||
EpochReceiver *placement.PlacementWrapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSessionService(p sessionParams) (session.Service, error) {
|
|
||||||
return session.New(session.Params{
|
|
||||||
TokenStore: p.TokenStore,
|
|
||||||
Logger: p.Logger,
|
|
||||||
EpochReceiver: p.EpochReceiver,
|
|
||||||
}), nil
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
protoTCP = "tcp"
|
|
||||||
protoUDP = "udp"
|
|
||||||
protoQUIC = "quic"
|
|
||||||
)
|
|
||||||
|
|
||||||
const emptyAddr = "0.0.0.0"
|
|
||||||
|
|
||||||
const ip4ColonCount = 1
|
|
||||||
|
|
||||||
var (
|
|
||||||
errEmptyAddress = errors.New("`node.address` could not be empty")
|
|
||||||
errEmptyProtocol = errors.New("`node.protocol` could not be empty")
|
|
||||||
errUnknownProtocol = errors.New("`node.protocol` unknown protocol")
|
|
||||||
errEmptyShutdownTTL = errors.New("`node.shutdown_ttl` could not be empty")
|
|
||||||
)
|
|
||||||
|
|
||||||
func ipVersion(address string) string {
|
|
||||||
if strings.Count(address, ":") > ip4ColonCount {
|
|
||||||
return "ip6"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "ip4"
|
|
||||||
}
|
|
||||||
|
|
||||||
func prepareAddress(address string) (string, error) {
|
|
||||||
host, port, err := net.SplitHostPort(address)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrapf(err, "could not fetch host/port: %s", address)
|
|
||||||
} else if host == "" {
|
|
||||||
host = emptyAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := net.ResolveIPAddr("ip", host)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrapf(err, "could not resolve address: %s:%s", host, port)
|
|
||||||
}
|
|
||||||
|
|
||||||
return net.JoinHostPort(addr.IP.String(), port), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveAddress(proto, address string) (string, string, error) {
|
|
||||||
var (
|
|
||||||
ip net.IP
|
|
||||||
host, port string
|
|
||||||
)
|
|
||||||
|
|
||||||
switch proto {
|
|
||||||
case protoTCP:
|
|
||||||
addr, err := net.ResolveTCPAddr(protoTCP, address)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", errors.Wrapf(err, "could not parse address: '%s'", address)
|
|
||||||
}
|
|
||||||
|
|
||||||
ip = addr.IP
|
|
||||||
port = strconv.Itoa(addr.Port)
|
|
||||||
case protoUDP, protoQUIC:
|
|
||||||
addr, err := net.ResolveUDPAddr(protoUDP, address)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", errors.Wrapf(err, "could not parse address: '%s'", address)
|
|
||||||
}
|
|
||||||
|
|
||||||
ip = addr.IP
|
|
||||||
port = strconv.Itoa(addr.Port)
|
|
||||||
default:
|
|
||||||
return "", "", errors.Wrapf(errUnknownProtocol, "unknown protocol: '%s'", proto)
|
|
||||||
}
|
|
||||||
|
|
||||||
if host = ip.String(); ip == nil {
|
|
||||||
host = emptyAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
return host, port, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func multiAddressFromProtoAddress(proto, addr string) (multiaddr.Multiaddr, error) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
host, port string
|
|
||||||
ipVer = ipVersion(addr)
|
|
||||||
)
|
|
||||||
|
|
||||||
if host, port, err = resolveAddress(proto, addr); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "could not resolve address: (%s) '%s'", proto, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
items := []string{
|
|
||||||
ipVer,
|
|
||||||
host,
|
|
||||||
proto,
|
|
||||||
port,
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = "/" + strings.Join(items, "/")
|
|
||||||
|
|
||||||
return multiaddr.NewMultiaddr(addr)
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package settings
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/module"
|
|
||||||
|
|
||||||
// Module is a node settings module.
|
|
||||||
var Module = module.Module{
|
|
||||||
{Constructor: newNodeSettings},
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
package settings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
|
||||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/network/peers"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
nodeSettings struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
Address multiaddr.Multiaddr
|
|
||||||
PrivateKey *ecdsa.PrivateKey
|
|
||||||
NodeOpts []string `name:"node_options"`
|
|
||||||
ShutdownTTL time.Duration `name:"shutdown_ttl"`
|
|
||||||
|
|
||||||
NodeInfo netmap.Info
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const generateKey = "generated"
|
|
||||||
|
|
||||||
var errEmptyNodeSettings = errors.New("node settings could not be empty")
|
|
||||||
|
|
||||||
func newNodeSettings(v *viper.Viper, l *zap.Logger) (cfg nodeSettings, err error) {
|
|
||||||
// check, that we have node settings in provided config
|
|
||||||
if !v.IsSet("node") {
|
|
||||||
err = errEmptyNodeSettings
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to load and setup ecdsa.PrivateKey
|
|
||||||
key := v.GetString("node.private_key")
|
|
||||||
switch key {
|
|
||||||
case "":
|
|
||||||
err = crypto.ErrEmptyPrivateKey
|
|
||||||
return cfg, err
|
|
||||||
case generateKey:
|
|
||||||
if cfg.PrivateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader); err != nil {
|
|
||||||
return cfg, err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if cfg.PrivateKey, err = crypto.LoadPrivateKey(key); err != nil {
|
|
||||||
return cfg, errors.Wrap(err, "cannot unmarshal private key")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
id := peers.IDFromPublicKey(&cfg.PrivateKey.PublicKey)
|
|
||||||
pub := crypto.MarshalPublicKey(&cfg.PrivateKey.PublicKey)
|
|
||||||
l.Debug("private key loaded successful",
|
|
||||||
zap.String("file", v.GetString("node.private_key")),
|
|
||||||
zap.Binary("public", pub),
|
|
||||||
zap.Stringer("node-id", id))
|
|
||||||
|
|
||||||
var (
|
|
||||||
addr string
|
|
||||||
proto string
|
|
||||||
)
|
|
||||||
|
|
||||||
// fetch shutdown timeout from settings
|
|
||||||
if cfg.ShutdownTTL = v.GetDuration("node.shutdown_ttl"); cfg.ShutdownTTL == 0 {
|
|
||||||
return cfg, errEmptyShutdownTTL
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch address and protocol from settings
|
|
||||||
if addr = v.GetString("node.address"); addr == "" {
|
|
||||||
return cfg, errors.Wrapf(errEmptyAddress, "given '%s'", addr)
|
|
||||||
} else if addr, err := prepareAddress(addr); err != nil {
|
|
||||||
return cfg, err
|
|
||||||
} else if proto = v.GetString("node.proto"); proto == "" {
|
|
||||||
return cfg, errors.Wrapf(errEmptyProtocol, "given '%s'", proto)
|
|
||||||
} else if cfg.Address, err = multiAddressFromProtoAddress(proto, addr); err != nil {
|
|
||||||
return cfg, errors.Wrapf(err, "given '%s' '%s'", proto, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add well-known options
|
|
||||||
items := map[string]string{
|
|
||||||
"Capacity": "capacity",
|
|
||||||
"Price": "price",
|
|
||||||
"Location": "location",
|
|
||||||
"Country": "country",
|
|
||||||
"City": "city",
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use const namings
|
|
||||||
prefix := "node."
|
|
||||||
|
|
||||||
for opt, path := range items {
|
|
||||||
val := v.GetString(prefix + path)
|
|
||||||
if len(val) == 0 {
|
|
||||||
err = errors.Errorf("node option %s must be set explicitly", opt)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.NodeOpts = append(cfg.NodeOpts,
|
|
||||||
fmt.Sprintf("/%s:%s",
|
|
||||||
opt,
|
|
||||||
val,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add other options
|
|
||||||
|
|
||||||
var (
|
|
||||||
i int
|
|
||||||
val string
|
|
||||||
)
|
|
||||||
loop:
|
|
||||||
for ; ; i++ {
|
|
||||||
val = v.GetString("node.options." + strconv.Itoa(i))
|
|
||||||
if val == "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
for opt := range items {
|
|
||||||
if strings.Contains(val, "/"+opt) {
|
|
||||||
continue loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.NodeOpts = append(cfg.NodeOpts, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeInfo := netmap.Info{}
|
|
||||||
nodeInfo.SetAddress(cfg.Address.String())
|
|
||||||
nodeInfo.SetPublicKey(crypto.MarshalPublicKey(&cfg.PrivateKey.PublicKey))
|
|
||||||
nodeInfo.SetOptions(cfg.NodeOpts)
|
|
||||||
|
|
||||||
cfg.NodeInfo = nodeInfo
|
|
||||||
|
|
||||||
l.Debug("loaded node options",
|
|
||||||
zap.Strings("options", cfg.NodeOpts))
|
|
||||||
|
|
||||||
return cfg, err
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package workers
|
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/module"
|
|
||||||
|
|
||||||
// Module is a workers module.
|
|
||||||
var Module = module.Module{
|
|
||||||
{Constructor: prepare},
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
package workers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-node/modules/fix/worker"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"go.uber.org/dig"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Result returns wrapped workers group for DI.
|
|
||||||
Result struct {
|
|
||||||
dig.Out
|
|
||||||
|
|
||||||
Workers []*worker.Job
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params is dependencies for create workers slice.
|
|
||||||
Params struct {
|
|
||||||
dig.In
|
|
||||||
|
|
||||||
Jobs worker.Jobs
|
|
||||||
Viper *viper.Viper
|
|
||||||
Logger *zap.Logger
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func prepare(p Params) worker.Workers {
|
|
||||||
w := worker.New()
|
|
||||||
|
|
||||||
for name, handler := range p.Jobs {
|
|
||||||
if job := byConfig(name, handler, p.Logger, p.Viper); job != nil {
|
|
||||||
p.Logger.Debug("worker: add new job",
|
|
||||||
zap.String("name", name))
|
|
||||||
|
|
||||||
w.Add(job)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
func byTicker(d time.Duration, h worker.Handler) worker.Handler {
|
|
||||||
return func(ctx context.Context) {
|
|
||||||
ticker := time.NewTicker(d)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
h(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func byTimer(d time.Duration, h worker.Handler) worker.Handler {
|
|
||||||
return func(ctx context.Context) {
|
|
||||||
timer := time.NewTimer(d)
|
|
||||||
defer timer.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case <-timer.C:
|
|
||||||
h(ctx)
|
|
||||||
timer.Reset(d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func byConfig(name string, h worker.Handler, l *zap.Logger, v *viper.Viper) worker.Handler {
|
|
||||||
var job worker.Handler
|
|
||||||
|
|
||||||
if !v.IsSet("workers." + name) {
|
|
||||||
l.Info("worker: has no configuration",
|
|
||||||
zap.String("worker", name))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.GetBool("workers." + name + ".disabled") {
|
|
||||||
l.Info("worker: disabled",
|
|
||||||
zap.String("worker", name))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if ticker := v.GetDuration("workers." + name + ".ticker"); ticker > 0 {
|
|
||||||
job = byTicker(ticker, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
if timer := v.GetDuration("workers." + name + ".timer"); timer > 0 {
|
|
||||||
job = byTimer(timer, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.GetBool("workers." + name + ".immediately") {
|
|
||||||
return func(ctx context.Context) {
|
|
||||||
h(ctx)
|
|
||||||
|
|
||||||
if job == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// check context before run immediately job again
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
job(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return job
|
|
||||||
}
|
|
0
pkg/core/container/.gitkeep
Normal file
0
pkg/core/container/.gitkeep
Normal file
|
@ -1,24 +0,0 @@
|
||||||
package basic
|
|
||||||
|
|
||||||
const (
|
|
||||||
// OpGetRangeHash is an index of GetRangeHash operation in basic ACL bitmask order.
|
|
||||||
OpGetRangeHash uint8 = iota
|
|
||||||
|
|
||||||
// OpGetRange is an index of GetRange operation in basic ACL bitmask order.
|
|
||||||
OpGetRange
|
|
||||||
|
|
||||||
// OpSearch is an index of Search operation in basic ACL bitmask order.
|
|
||||||
OpSearch
|
|
||||||
|
|
||||||
// OpDelete is an index of Delete operation in basic ACL bitmask order.
|
|
||||||
OpDelete
|
|
||||||
|
|
||||||
// OpPut is an index of Put operation in basic ACL bitmask order.
|
|
||||||
OpPut
|
|
||||||
|
|
||||||
// OpHead is an index of Head operation in basic ACL bitmask order.
|
|
||||||
OpHead
|
|
||||||
|
|
||||||
// OpGet is an index of Get operation in basic ACL bitmask order.
|
|
||||||
OpGet
|
|
||||||
)
|
|
|
@ -1,159 +0,0 @@
|
||||||
package basic
|
|
||||||
|
|
||||||
// ACL represents a container's
|
|
||||||
// basic permission bits.
|
|
||||||
type ACL uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
reservedBitNumber = 2 // first left bits are reserved
|
|
||||||
|
|
||||||
stickyBitPos = reservedBitNumber // X-bit after reserved bits
|
|
||||||
|
|
||||||
finalBitPos = stickyBitPos + 1 // F-bit after X-bit
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
opOffset = finalBitPos + 1 // offset of operation bits
|
|
||||||
|
|
||||||
bitsPerOp = 4 // number of bits per operation
|
|
||||||
|
|
||||||
opNumber = 7 // number of operation bit sections
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
bitUser uint8 = iota
|
|
||||||
bitSystem
|
|
||||||
bitOthers
|
|
||||||
bitBearer
|
|
||||||
)
|
|
||||||
|
|
||||||
const leftACLBitPos = opOffset + bitsPerOp*opNumber - 1
|
|
||||||
|
|
||||||
// returns true if n-th left bit is set (starting at 0).
|
|
||||||
func isLeftBitSet(value ACL, n uint8) bool {
|
|
||||||
bitMask := ACL(1 << (leftACLBitPos - n))
|
|
||||||
return bitMask != 0 && value&bitMask == bitMask
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets n-th left bit (starting at 0).
|
|
||||||
func setLeftBit(value *ACL, n uint8) {
|
|
||||||
*value |= ACL(1 << (leftACLBitPos - n))
|
|
||||||
}
|
|
||||||
|
|
||||||
// resets n-th left bit (starting at 0).
|
|
||||||
func resetLeftBit(value *ACL, n uint8) {
|
|
||||||
*value &= ^ACL(1 << (leftACLBitPos - n))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reserved returns true if n-th reserved option is enabled in basic ACL.
|
|
||||||
func (a ACL) Reserved(n uint8) bool {
|
|
||||||
return n < reservedBitNumber && isLeftBitSet(a, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetReserved enables the n-th reserved option in basic ACL.
|
|
||||||
func (a *ACL) SetReserved(bit uint8) {
|
|
||||||
if bit < reservedBitNumber {
|
|
||||||
setLeftBit(a, bit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetReserved disables the n-th reserved option in basic ACL.
|
|
||||||
func (a *ACL) ResetReserved(bit uint8) {
|
|
||||||
if bit < reservedBitNumber {
|
|
||||||
resetLeftBit(a, bit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final returns true if final option is enabled in basic ACL.
|
|
||||||
func (a ACL) Final() bool {
|
|
||||||
return isLeftBitSet(a, finalBitPos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFinal enables final option in basic ACL.
|
|
||||||
func (a *ACL) SetFinal() {
|
|
||||||
setLeftBit(a, finalBitPos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetFinal disables final option in basic ACL.
|
|
||||||
func (a *ACL) ResetFinal() {
|
|
||||||
resetLeftBit(a, finalBitPos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sticky returns true if sticky option is enabled in basic ACL.
|
|
||||||
func (a ACL) Sticky() bool {
|
|
||||||
return isLeftBitSet(a, stickyBitPos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSticky enables the sticky option in basic ACL.
|
|
||||||
func (a *ACL) SetSticky() {
|
|
||||||
setLeftBit(a, stickyBitPos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetSticky disables the sticky option in basic ACL.
|
|
||||||
func (a *ACL) ResetSticky() {
|
|
||||||
resetLeftBit(a, stickyBitPos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserAllowed returns true if user allowed the n-th operation in basic ACL.
|
|
||||||
func (a ACL) UserAllowed(n uint8) bool {
|
|
||||||
return isLeftBitSet(a, opOffset+n*bitsPerOp+bitUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowUser allows user the n-th operation in basic ACL.
|
|
||||||
func (a *ACL) AllowUser(n uint8) {
|
|
||||||
setLeftBit(a, opOffset+n*bitsPerOp+bitUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForbidUser forbids user the n-th operation in basic ACL.
|
|
||||||
func (a *ACL) ForbidUser(n uint8) {
|
|
||||||
resetLeftBit(a, opOffset+n*bitsPerOp+bitUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemAllowed returns true if System group allowed the n-th operation is set in basic ACL.
|
|
||||||
func (a ACL) SystemAllowed(n uint8) bool {
|
|
||||||
if n != OpDelete && n != OpGetRange {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return isLeftBitSet(a, opOffset+n*bitsPerOp+bitSystem)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowSystem allows System group the n-th operation in basic ACL.
|
|
||||||
func (a *ACL) AllowSystem(op uint8) {
|
|
||||||
setLeftBit(a, opOffset+op*bitsPerOp+bitSystem)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForbidSystem forbids System group the n-th operation in basic ACL.
|
|
||||||
func (a *ACL) ForbidSystem(op uint8) {
|
|
||||||
resetLeftBit(a, opOffset+op*bitsPerOp+bitSystem)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OthersAllowed returns true if Others group allowed the n-th operation is set in basic ACL.
|
|
||||||
func (a ACL) OthersAllowed(op uint8) bool {
|
|
||||||
return isLeftBitSet(a, opOffset+op*bitsPerOp+bitOthers)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowOthers allows Others group the n-th operation in basic ACL.
|
|
||||||
func (a *ACL) AllowOthers(op uint8) {
|
|
||||||
setLeftBit(a, opOffset+op*bitsPerOp+bitOthers)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForbidOthers forbids Others group the n-th operation in basic ACL.
|
|
||||||
func (a *ACL) ForbidOthers(op uint8) {
|
|
||||||
resetLeftBit(a, opOffset+op*bitsPerOp+bitOthers)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BearerAllowed returns true if Bearer token usage is allowed for n-th operation in basic ACL.
|
|
||||||
func (a ACL) BearerAllowed(op uint8) bool {
|
|
||||||
return isLeftBitSet(a, opOffset+op*bitsPerOp+bitBearer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowBearer allows Bearer token usage for n-th operation in basic ACL.
|
|
||||||
func (a *ACL) AllowBearer(op uint8) {
|
|
||||||
setLeftBit(a, opOffset+op*bitsPerOp+bitBearer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForbidBearer forbids Bearer token usage for n-th operation in basic ACL.
|
|
||||||
func (a *ACL) ForbidBearer(op uint8) {
|
|
||||||
resetLeftBit(a, opOffset+op*bitsPerOp+bitBearer)
|
|
||||||
}
|
|
|
@ -1,189 +0,0 @@
|
||||||
package basic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestACLValues(t *testing.T) {
|
|
||||||
t.Run("private", func(t *testing.T) {
|
|
||||||
acl := FromUint32(0x1C8C8CCC)
|
|
||||||
|
|
||||||
require.False(t, acl.Reserved(0))
|
|
||||||
require.False(t, acl.Reserved(1))
|
|
||||||
require.False(t, acl.Sticky())
|
|
||||||
require.True(t, acl.Final())
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGetRangeHash))
|
|
||||||
require.True(t, acl.SystemAllowed(OpGetRangeHash))
|
|
||||||
require.False(t, acl.OthersAllowed(OpGetRangeHash))
|
|
||||||
require.False(t, acl.BearerAllowed(OpGetRangeHash))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGetRange))
|
|
||||||
require.False(t, acl.SystemAllowed(OpGetRange))
|
|
||||||
require.False(t, acl.OthersAllowed(OpGetRange))
|
|
||||||
require.False(t, acl.BearerAllowed(OpGetRange))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpSearch))
|
|
||||||
require.True(t, acl.SystemAllowed(OpSearch))
|
|
||||||
require.False(t, acl.OthersAllowed(OpSearch))
|
|
||||||
require.False(t, acl.BearerAllowed(OpSearch))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpDelete))
|
|
||||||
require.False(t, acl.SystemAllowed(OpDelete))
|
|
||||||
require.False(t, acl.OthersAllowed(OpDelete))
|
|
||||||
require.False(t, acl.BearerAllowed(OpDelete))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpPut))
|
|
||||||
require.True(t, acl.SystemAllowed(OpPut))
|
|
||||||
require.False(t, acl.OthersAllowed(OpPut))
|
|
||||||
require.False(t, acl.BearerAllowed(OpPut))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpHead))
|
|
||||||
require.True(t, acl.SystemAllowed(OpHead))
|
|
||||||
require.False(t, acl.OthersAllowed(OpHead))
|
|
||||||
require.False(t, acl.BearerAllowed(OpHead))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGet))
|
|
||||||
require.True(t, acl.SystemAllowed(OpGet))
|
|
||||||
require.False(t, acl.OthersAllowed(OpGet))
|
|
||||||
require.False(t, acl.BearerAllowed(OpGet))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("public with X-bit", func(t *testing.T) {
|
|
||||||
acl := FromUint32(0x3FFFFFFF)
|
|
||||||
|
|
||||||
require.False(t, acl.Reserved(0))
|
|
||||||
require.False(t, acl.Reserved(1))
|
|
||||||
require.True(t, acl.Sticky())
|
|
||||||
require.True(t, acl.Final())
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGetRangeHash))
|
|
||||||
require.True(t, acl.SystemAllowed(OpGetRangeHash))
|
|
||||||
require.True(t, acl.OthersAllowed(OpGetRangeHash))
|
|
||||||
require.True(t, acl.BearerAllowed(OpGetRangeHash))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGetRange))
|
|
||||||
require.True(t, acl.SystemAllowed(OpGetRange))
|
|
||||||
require.True(t, acl.OthersAllowed(OpGetRange))
|
|
||||||
require.True(t, acl.BearerAllowed(OpGetRange))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpSearch))
|
|
||||||
require.True(t, acl.SystemAllowed(OpSearch))
|
|
||||||
require.True(t, acl.OthersAllowed(OpSearch))
|
|
||||||
require.True(t, acl.BearerAllowed(OpSearch))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpDelete))
|
|
||||||
require.True(t, acl.SystemAllowed(OpDelete))
|
|
||||||
require.True(t, acl.OthersAllowed(OpDelete))
|
|
||||||
require.True(t, acl.BearerAllowed(OpDelete))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpPut))
|
|
||||||
require.True(t, acl.SystemAllowed(OpPut))
|
|
||||||
require.True(t, acl.OthersAllowed(OpPut))
|
|
||||||
require.True(t, acl.BearerAllowed(OpPut))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpHead))
|
|
||||||
require.True(t, acl.SystemAllowed(OpHead))
|
|
||||||
require.True(t, acl.OthersAllowed(OpHead))
|
|
||||||
require.True(t, acl.BearerAllowed(OpHead))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGet))
|
|
||||||
require.True(t, acl.SystemAllowed(OpGet))
|
|
||||||
require.True(t, acl.OthersAllowed(OpGet))
|
|
||||||
require.True(t, acl.BearerAllowed(OpGet))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("read only", func(t *testing.T) {
|
|
||||||
acl := FromUint32(0x1FFFCCFF)
|
|
||||||
|
|
||||||
require.False(t, acl.Reserved(0))
|
|
||||||
require.False(t, acl.Reserved(1))
|
|
||||||
require.False(t, acl.Sticky())
|
|
||||||
require.True(t, acl.Final())
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGetRangeHash))
|
|
||||||
require.True(t, acl.SystemAllowed(OpGetRangeHash))
|
|
||||||
require.True(t, acl.OthersAllowed(OpGetRangeHash))
|
|
||||||
require.True(t, acl.BearerAllowed(OpGetRangeHash))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGetRange))
|
|
||||||
require.True(t, acl.SystemAllowed(OpGetRange))
|
|
||||||
require.True(t, acl.OthersAllowed(OpGetRange))
|
|
||||||
require.True(t, acl.BearerAllowed(OpGetRange))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpSearch))
|
|
||||||
require.True(t, acl.SystemAllowed(OpSearch))
|
|
||||||
require.True(t, acl.OthersAllowed(OpSearch))
|
|
||||||
require.True(t, acl.BearerAllowed(OpSearch))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpDelete))
|
|
||||||
require.True(t, acl.SystemAllowed(OpDelete))
|
|
||||||
require.False(t, acl.OthersAllowed(OpDelete))
|
|
||||||
require.False(t, acl.BearerAllowed(OpDelete))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpPut))
|
|
||||||
require.True(t, acl.SystemAllowed(OpPut))
|
|
||||||
require.False(t, acl.OthersAllowed(OpPut))
|
|
||||||
require.False(t, acl.BearerAllowed(OpPut))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpHead))
|
|
||||||
require.True(t, acl.SystemAllowed(OpHead))
|
|
||||||
require.True(t, acl.OthersAllowed(OpHead))
|
|
||||||
require.True(t, acl.BearerAllowed(OpHead))
|
|
||||||
|
|
||||||
require.True(t, acl.UserAllowed(OpGet))
|
|
||||||
require.True(t, acl.SystemAllowed(OpGet))
|
|
||||||
require.True(t, acl.OthersAllowed(OpGet))
|
|
||||||
require.True(t, acl.BearerAllowed(OpGet))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestACLMethods(t *testing.T) {
|
|
||||||
acl := new(ACL)
|
|
||||||
|
|
||||||
for i := uint8(0); i < reservedBitNumber; i++ {
|
|
||||||
acl.SetReserved(i)
|
|
||||||
require.True(t, acl.Reserved(i))
|
|
||||||
acl.ResetReserved(i)
|
|
||||||
require.False(t, acl.Reserved(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
acl.SetSticky()
|
|
||||||
require.True(t, acl.Sticky())
|
|
||||||
acl.ResetSticky()
|
|
||||||
require.False(t, acl.Sticky())
|
|
||||||
|
|
||||||
acl.SetFinal()
|
|
||||||
require.True(t, acl.Final())
|
|
||||||
acl.ResetFinal()
|
|
||||||
require.False(t, acl.Final())
|
|
||||||
|
|
||||||
for i := OpGetRangeHash; i <= OpGet; i++ {
|
|
||||||
acl.AllowUser(i)
|
|
||||||
require.True(t, acl.UserAllowed(i))
|
|
||||||
acl.ForbidUser(i)
|
|
||||||
require.False(t, acl.UserAllowed(i))
|
|
||||||
|
|
||||||
acl.AllowOthers(i)
|
|
||||||
require.True(t, acl.OthersAllowed(i))
|
|
||||||
acl.ForbidOthers(i)
|
|
||||||
require.False(t, acl.OthersAllowed(i))
|
|
||||||
|
|
||||||
acl.AllowBearer(i)
|
|
||||||
require.True(t, acl.BearerAllowed(i))
|
|
||||||
acl.ForbidBearer(i)
|
|
||||||
require.False(t, acl.BearerAllowed(i))
|
|
||||||
|
|
||||||
acl.AllowSystem(i)
|
|
||||||
require.True(t, acl.SystemAllowed(i))
|
|
||||||
acl.ForbidSystem(i)
|
|
||||||
|
|
||||||
if i == OpDelete || i == OpGetRange {
|
|
||||||
require.False(t, acl.SystemAllowed(i))
|
|
||||||
} else {
|
|
||||||
require.True(t, acl.SystemAllowed(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package basic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Size is a size of ACL
|
|
||||||
// in a binary form.
|
|
||||||
const Size = 4
|
|
||||||
|
|
||||||
// FromUint32 converts builtin
|
|
||||||
// uint32 value to ACL.
|
|
||||||
//
|
|
||||||
// Try to avoid direct cast for
|
|
||||||
// better portability.
|
|
||||||
func FromUint32(v uint32) ACL {
|
|
||||||
return ACL(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToUint32 converts ACL value
|
|
||||||
// to builtin uint32.
|
|
||||||
//
|
|
||||||
// Try to avoid direct cast for
|
|
||||||
// better portability.
|
|
||||||
func ToUint32(v ACL) uint32 {
|
|
||||||
return uint32(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal reports whether e and e2 are the same ACL.
|
|
||||||
//
|
|
||||||
// Function defines the relation of equality
|
|
||||||
// between two ACL. Try to avoid comparison through
|
|
||||||
// "==" operator for better portability.
|
|
||||||
func Equal(a, b ACL) bool {
|
|
||||||
return ToUint32(a) == ToUint32(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal encodes ACL into a
|
|
||||||
// binary form and returns the result.
|
|
||||||
//
|
|
||||||
// Result slice has Size length.
|
|
||||||
func Marshal(a ACL) []byte {
|
|
||||||
d := make([]byte, Size)
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(d, ToUint32(a))
|
|
||||||
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBinary unmarshals ACL from
|
|
||||||
// a binary representation.
|
|
||||||
//
|
|
||||||
// If buffer size is insufficient,
|
|
||||||
// io.ErrUnexpectedEOF is returned.
|
|
||||||
func (a *ACL) UnmarshalBinary(data []byte) error {
|
|
||||||
if len(data) < Size {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
|
|
||||||
*a = FromUint32(binary.BigEndian.Uint32(data))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package basic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEqual(t *testing.T) {
|
|
||||||
require.True(t,
|
|
||||||
Equal(
|
|
||||||
FromUint32(1),
|
|
||||||
FromUint32(1),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
require.False(t,
|
|
||||||
Equal(
|
|
||||||
FromUint32(1),
|
|
||||||
FromUint32(2),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMarshal(t *testing.T) {
|
|
||||||
a := FromUint32(1)
|
|
||||||
a2 := new(ACL)
|
|
||||||
|
|
||||||
require.NoError(t,
|
|
||||||
a2.UnmarshalBinary(
|
|
||||||
Marshal(a),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
require.True(t, Equal(a, *a2))
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CID represents the container identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
|
||||||
type CID = container.ID
|
|
||||||
|
|
||||||
// Table represents extended ACL rule table.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/eacl/extended.Table.
|
|
||||||
type Table = eacl.Table
|
|
||||||
|
|
||||||
// Storage is the interface that wraps
|
|
||||||
// basic methods of extended ACL table storage.
|
|
||||||
type Storage interface {
|
|
||||||
// GetEACL reads the table from the storage by identifier.
|
|
||||||
// It returns any error encountered.
|
|
||||||
//
|
|
||||||
// GetEACL must return exactly one non-nil value.
|
|
||||||
// GetEACL must return ErrNotFound if the table is not in storage.
|
|
||||||
//
|
|
||||||
// Implementations must not retain or modify the table
|
|
||||||
// (even temporarily).
|
|
||||||
GetEACL(CID) (Table, error)
|
|
||||||
|
|
||||||
// PutEACL saves the table to the underlying storage.
|
|
||||||
// It returns any error encountered that caused the saving to interrupt.
|
|
||||||
//
|
|
||||||
// PutEACL must return extended.ErrNilTable on nil table.
|
|
||||||
//
|
|
||||||
// Implementations must not retain or modify the table (even temporarily).
|
|
||||||
//
|
|
||||||
// Table rewriting behavior is dictated by implementation.
|
|
||||||
PutEACL(CID, Table, []byte) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNotFound is the error returned when eACL table
|
|
||||||
// was not found in storage.
|
|
||||||
var ErrNotFound = errors.New("container not found")
|
|
||||||
|
|
||||||
// ErrNilStorage is the error returned by functions that
|
|
||||||
// expect a non-nil eACL table storage implementation,
|
|
||||||
// but received nil.
|
|
||||||
var ErrNilStorage = errors.New("eACL storage is nil")
|
|
|
@ -1,48 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testStorage struct {
|
|
||||||
*sync.RWMutex
|
|
||||||
|
|
||||||
items map[container.ID]storage.Table
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) GetEACL(cid storage.CID) (storage.Table, error) {
|
|
||||||
s.RLock()
|
|
||||||
table, ok := s.items[cid]
|
|
||||||
s.RUnlock()
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil, storage.ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return table, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) PutEACL(cid storage.CID, table storage.Table, _ []byte) error {
|
|
||||||
if table == nil {
|
|
||||||
return extended.ErrNilTable
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Lock()
|
|
||||||
s.items[cid] = table
|
|
||||||
s.Unlock()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates new eACL table storage
|
|
||||||
// that stores table in go-builtin map.
|
|
||||||
func New() storage.Storage {
|
|
||||||
return &testStorage{
|
|
||||||
RWMutex: new(sync.RWMutex),
|
|
||||||
items: make(map[container.ID]storage.Table),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,102 +0,0 @@
|
||||||
package extended
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FIXME: do not duplicate constants
|
|
||||||
|
|
||||||
// OperationType represents the enumeration
|
|
||||||
// of different destination types of request.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-api-go/eacl.OperationType.
|
|
||||||
// FIXME: operation type should be defined in core lib.
|
|
||||||
type OperationType = eacl.OperationType
|
|
||||||
|
|
||||||
// Group represents the enumeration
|
|
||||||
// of different authorization groups.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-api-go/acl/extended.Group.
|
|
||||||
// FIXME: target should be defined in core lib.
|
|
||||||
type Group = eacl.Group
|
|
||||||
|
|
||||||
// HeaderType represents the enumeration
|
|
||||||
// of different types of header.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-api-go/eacl.HeaderType.
|
|
||||||
// FIXME: header type enum should be defined in core lib.
|
|
||||||
type HeaderType = eacl.HeaderType
|
|
||||||
|
|
||||||
// CID represents the container identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
|
||||||
type CID = container.ID
|
|
||||||
|
|
||||||
// Header is an interface that wraps
|
|
||||||
// methods of string key-value header.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-api-go/eacl.Header.
|
|
||||||
// FIXME: header should be defined in core lib.
|
|
||||||
type Header = eacl.Header
|
|
||||||
|
|
||||||
// Table represents extended ACL rule table.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-api-go/eacl.ExtendedACLTable.
|
|
||||||
// FIXME: eacl table should be defined in core package.
|
|
||||||
// type Table = eacl.ExtendedACLTable
|
|
||||||
|
|
||||||
// TypedHeaderSource is the interface that wraps
|
|
||||||
// method for selecting typed headers by type.
|
|
||||||
type TypedHeaderSource interface {
|
|
||||||
// HeadersOfType returns the list of key-value headers
|
|
||||||
// of particular type.
|
|
||||||
//
|
|
||||||
// It returns any problem encountered through the boolean
|
|
||||||
// false value.
|
|
||||||
HeadersOfType(HeaderType) ([]Header, bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestInfo is an interface that wraps
|
|
||||||
// request with authority methods.
|
|
||||||
type RequestInfo interface {
|
|
||||||
TypedHeaderSource
|
|
||||||
|
|
||||||
// CID returns container identifier from request context.
|
|
||||||
CID() CID
|
|
||||||
|
|
||||||
// Key returns the binary representation of
|
|
||||||
// author's public key.
|
|
||||||
//
|
|
||||||
// Any problem encountered can be reflected
|
|
||||||
// through an empty slice.
|
|
||||||
//
|
|
||||||
// Binary key format is dictated by implementation.
|
|
||||||
Key() []byte
|
|
||||||
|
|
||||||
// OperationType returns the type of request destination.
|
|
||||||
//
|
|
||||||
// Any problem encountered can be reflected
|
|
||||||
// through OpTypeUnknown value. Caller should handle
|
|
||||||
// OpTypeUnknown value according to its internal logic.
|
|
||||||
OperationType() OperationType
|
|
||||||
|
|
||||||
// Group returns the authority group type.
|
|
||||||
//
|
|
||||||
// Any problem encountered can be reflected
|
|
||||||
// through GroupUnknown value. Caller should handle
|
|
||||||
// TargetUnknown value according to its internal logic.
|
|
||||||
Group() Group
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNilTable is the error returned by functions that
|
|
||||||
// expect a non-nil eACL table, but received nil.
|
|
||||||
var ErrNilTable = errors.New("eACL table is nil")
|
|
|
@ -1,82 +0,0 @@
|
||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
|
||||||
"github.com/nspcc-dev/netmap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BasicACL represents the basic
|
|
||||||
// ACL rules.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/basic.ACL.
|
|
||||||
type BasicACL = basic.ACL
|
|
||||||
|
|
||||||
// PlacementRule represents placement
|
|
||||||
// rules of the container.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/netmap.PlacementRule.
|
|
||||||
// FIXME: container placement rules should be defined in core lib.
|
|
||||||
type PlacementRule = netmap.PlacementRule
|
|
||||||
|
|
||||||
// Container represents NeoFS container.
|
|
||||||
type Container struct {
|
|
||||||
basicACL BasicACL // basic ACL mask
|
|
||||||
|
|
||||||
ownerID OwnerID // the identifier of container's owner
|
|
||||||
|
|
||||||
salt []byte // unique container bytes
|
|
||||||
|
|
||||||
placementRule PlacementRule // placement rules
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNilContainer is the error returned by functions that
|
|
||||||
// expect a non-nil container pointer, but received nil.
|
|
||||||
var ErrNilContainer = errors.New("container is nil")
|
|
||||||
|
|
||||||
// OwnerID returns an ID of the container's owner.
|
|
||||||
func (c *Container) OwnerID() OwnerID {
|
|
||||||
return c.ownerID
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOwnerID sets the ID of the container's owner.
|
|
||||||
func (c *Container) SetOwnerID(v OwnerID) {
|
|
||||||
c.ownerID = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Salt returns the container salt.
|
|
||||||
//
|
|
||||||
// Slice is returned by reference without copying.
|
|
||||||
func (c *Container) Salt() []byte {
|
|
||||||
return c.salt
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSalt sets the container salt.
|
|
||||||
//
|
|
||||||
// Slice is assigned by reference without copying.
|
|
||||||
func (c *Container) SetSalt(v []byte) {
|
|
||||||
c.salt = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// BasicACL returns the mask of basic container permissions.
|
|
||||||
func (c *Container) BasicACL() BasicACL {
|
|
||||||
return c.basicACL
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBasicACL sets the mask of basic container permissions.
|
|
||||||
func (c *Container) SetBasicACL(v BasicACL) {
|
|
||||||
c.basicACL = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// PlacementRule returns placement rule of the container.
|
|
||||||
func (c *Container) PlacementRule() PlacementRule {
|
|
||||||
return c.placementRule
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPlacementRule sets placement rule of the container.
|
|
||||||
func (c *Container) SetPlacementRule(v PlacementRule) {
|
|
||||||
c.placementRule = v
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestContainerMethods(t *testing.T) {
|
|
||||||
c := new(Container)
|
|
||||||
|
|
||||||
acl := basic.FromUint32(1)
|
|
||||||
c.SetBasicACL(acl)
|
|
||||||
require.True(t, basic.Equal(acl, c.BasicACL()))
|
|
||||||
|
|
||||||
ownerID := OwnerID{1, 2, 3}
|
|
||||||
c.SetOwnerID(ownerID)
|
|
||||||
require.Equal(t, ownerID, c.OwnerID())
|
|
||||||
|
|
||||||
salt := []byte{4, 5, 6}
|
|
||||||
c.SetSalt(salt)
|
|
||||||
require.Equal(t, salt, c.Salt())
|
|
||||||
|
|
||||||
rule := PlacementRule{
|
|
||||||
ReplFactor: 1,
|
|
||||||
}
|
|
||||||
c.SetPlacementRule(rule)
|
|
||||||
require.Equal(t, rule, c.PlacementRule())
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ID represents the
|
|
||||||
// container identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-api-go/refs.CID.
|
|
||||||
// FIXME: container id should be defined in core package.
|
|
||||||
type ID = refs.CID
|
|
||||||
|
|
||||||
// OwnerID represents the
|
|
||||||
// container owner identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-api-go/refs.OwnerID.
|
|
||||||
// FIXME: owner ID should be defined in core lib.
|
|
||||||
type OwnerID = refs.OwnerID
|
|
||||||
|
|
||||||
// OwnerIDSize is a size of OwnerID
|
|
||||||
// in a binary form.
|
|
||||||
const OwnerIDSize = refs.OwnerIDSize
|
|
||||||
|
|
||||||
// CalculateID calculates container identifier
|
|
||||||
// as SHA256 checksum of the binary form.
|
|
||||||
//
|
|
||||||
// If container is nil, ErrNilContainer is returned.
|
|
||||||
func CalculateID(cnr *Container) (*ID, error) {
|
|
||||||
if cnr == nil {
|
|
||||||
return nil, ErrNilContainer
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := cnr.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := new(ID)
|
|
||||||
sh := sha256.Sum256(data)
|
|
||||||
|
|
||||||
copy(res[:], sh[:])
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCalculateID(t *testing.T) {
|
|
||||||
_, err := CalculateID(nil)
|
|
||||||
require.True(t, errors.Is(err, ErrNilContainer))
|
|
||||||
|
|
||||||
cnr := new(Container)
|
|
||||||
cnr.SetBasicACL(basic.FromUint32(1))
|
|
||||||
cnr.SetOwnerID(OwnerID{1, 2, 3})
|
|
||||||
cnr.SetSalt([]byte{4, 5, 6})
|
|
||||||
|
|
||||||
id1, err := CalculateID(cnr)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
data, err := cnr.MarshalBinary()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
sh := sha256.Sum256(data)
|
|
||||||
|
|
||||||
require.Equal(t, id1.Bytes(), sh[:])
|
|
||||||
|
|
||||||
// change the container
|
|
||||||
cnr.SetSalt(append(cnr.Salt(), 1))
|
|
||||||
|
|
||||||
id2, err := CalculateID(cnr)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.NotEqual(t, id1, id2)
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
saltLenSize = 2
|
|
||||||
|
|
||||||
fixedSize = 0 +
|
|
||||||
basic.Size +
|
|
||||||
OwnerIDSize +
|
|
||||||
saltLenSize
|
|
||||||
)
|
|
||||||
|
|
||||||
// MarshalBinary encodes the container into a binary form
|
|
||||||
// and returns the result.
|
|
||||||
func (c *Container) MarshalBinary() ([]byte, error) {
|
|
||||||
data := make([]byte, binaryContainerSize(c))
|
|
||||||
|
|
||||||
off := copy(data, basic.Marshal(c.basicACL))
|
|
||||||
|
|
||||||
off += copy(data[off:], c.ownerID.Bytes())
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint16(data[off:], uint16(len(c.salt)))
|
|
||||||
off += saltLenSize
|
|
||||||
|
|
||||||
off += copy(data[off:], c.salt)
|
|
||||||
|
|
||||||
if _, err := c.placementRule.MarshalTo(data[off:]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBinary unmarshals container from a binary
|
|
||||||
// representation.
|
|
||||||
//
|
|
||||||
// If buffer size is insufficient, io.ErrUnexpectedEOF is returned.
|
|
||||||
func (c *Container) UnmarshalBinary(data []byte) error {
|
|
||||||
if len(data) < binaryContainerSize(c) {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.basicACL.UnmarshalBinary(data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
off := basic.Size
|
|
||||||
|
|
||||||
off += copy(c.ownerID[:], data[off:])
|
|
||||||
|
|
||||||
saltLen := binary.BigEndian.Uint16(data[off:])
|
|
||||||
off += saltLenSize
|
|
||||||
|
|
||||||
c.salt = make([]byte, saltLen)
|
|
||||||
off += copy(c.salt, data[off:])
|
|
||||||
|
|
||||||
if err := c.placementRule.Unmarshal(data[off:]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the length of the container in binary form.
|
|
||||||
func binaryContainerSize(cnr *Container) int {
|
|
||||||
return fixedSize +
|
|
||||||
len(cnr.salt) +
|
|
||||||
cnr.placementRule.Size()
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestContainerMarshal(t *testing.T) {
|
|
||||||
srcCnr := new(Container)
|
|
||||||
srcCnr.SetBasicACL(basic.FromUint32(1))
|
|
||||||
srcCnr.SetOwnerID(OwnerID{1, 2, 3})
|
|
||||||
srcCnr.SetSalt([]byte{4, 5, 6})
|
|
||||||
srcCnr.SetPlacementRule(PlacementRule{
|
|
||||||
ReplFactor: 3,
|
|
||||||
})
|
|
||||||
|
|
||||||
data, err := srcCnr.MarshalBinary()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
dstCnr := new(Container)
|
|
||||||
require.NoError(t, dstCnr.UnmarshalBinary(data))
|
|
||||||
|
|
||||||
require.Equal(t, srcCnr, dstCnr)
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Container represents the NeoFS container.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.Container.
|
|
||||||
type Container = container.Container
|
|
||||||
|
|
||||||
// OwnerID represents the container
|
|
||||||
// owner identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.OwnerID.
|
|
||||||
type OwnerID = container.OwnerID
|
|
||||||
|
|
||||||
// CID represents the container identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
|
||||||
type CID = container.ID
|
|
||||||
|
|
||||||
// Storage is an interface that wraps
|
|
||||||
// basic container storage methods.
|
|
||||||
type Storage interface {
|
|
||||||
// Put saves pointed container to the underlying storage.
|
|
||||||
// It returns calculated container identifier and any error
|
|
||||||
// encountered that caused the saving to interrupt.
|
|
||||||
//
|
|
||||||
// Put must return container.ErrNilContainer on nil-pointer.
|
|
||||||
//
|
|
||||||
// Implementations must not modify the container through the pointer (even temporarily).
|
|
||||||
// Implementations must not retain the container pointer.
|
|
||||||
//
|
|
||||||
// Container rewriting behavior is dictated by implementation.
|
|
||||||
Put(*Container) (*CID, error)
|
|
||||||
|
|
||||||
// Get reads the container from the storage by identifier.
|
|
||||||
// It returns the pointer to requested container and any error encountered.
|
|
||||||
//
|
|
||||||
// Get must return exactly one non-nil value.
|
|
||||||
// Get must return ErrNotFound if the container is not in storage.
|
|
||||||
//
|
|
||||||
// Implementations must not retain the container pointer and modify
|
|
||||||
// the container through it.
|
|
||||||
Get(CID) (*Container, error)
|
|
||||||
|
|
||||||
// Delete removes the container from the storage.
|
|
||||||
// It returns any error encountered that caused the deletion to interrupt.
|
|
||||||
//
|
|
||||||
// Delete must return nil if container was successfully deleted.
|
|
||||||
//
|
|
||||||
// Behavior when deleting a nonexistent container is dictated by implementation.
|
|
||||||
Delete(CID) error
|
|
||||||
|
|
||||||
// List returns a list of container identifiers belonging to the specified owner.
|
|
||||||
// It returns any error encountered that caused the listing to interrupt.
|
|
||||||
//
|
|
||||||
// List must return the identifiers of all stored containers if owner pointer is nil.
|
|
||||||
// List must return the empty list and no error in the absence of containers in storage.
|
|
||||||
//
|
|
||||||
// Result slice can be either empty slice or nil, so empty list should be checked
|
|
||||||
// by comparing with zero length (not nil).
|
|
||||||
//
|
|
||||||
// Callers should carefully handle the incomplete list in case of interrupt error.
|
|
||||||
List(*OwnerID) ([]CID, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNotFound is the error returned when container was not found in storage.
|
|
||||||
var ErrNotFound = errors.New("container not found")
|
|
||||||
|
|
||||||
// ErrNilStorage is the error returned by functions that
|
|
||||||
// expect a non-nil container storage implementation, but received nil.
|
|
||||||
var ErrNilStorage = errors.New("container storage is nil")
|
|
|
@ -1,127 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testStorage struct {
|
|
||||||
*sync.RWMutex
|
|
||||||
|
|
||||||
items map[container.ID]*container.Container
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) Put(cnr *storage.Container) (*storage.CID, error) {
|
|
||||||
if cnr == nil {
|
|
||||||
return nil, container.ErrNilContainer
|
|
||||||
}
|
|
||||||
|
|
||||||
cid, err := container.CalculateID(cnr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Lock()
|
|
||||||
s.items[*cid] = cnr
|
|
||||||
s.Unlock()
|
|
||||||
|
|
||||||
return cid, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) Get(cid storage.CID) (*storage.Container, error) {
|
|
||||||
s.RLock()
|
|
||||||
cnr, ok := s.items[cid]
|
|
||||||
s.RUnlock()
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil, storage.ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return cnr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) Delete(cid storage.CID) error {
|
|
||||||
s.Lock()
|
|
||||||
delete(s.items, cid)
|
|
||||||
s.Unlock()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) List(ownerID *storage.OwnerID) ([]storage.CID, error) {
|
|
||||||
s.RLock()
|
|
||||||
defer s.RUnlock()
|
|
||||||
|
|
||||||
res := make([]storage.CID, 0)
|
|
||||||
|
|
||||||
for cid, cnr := range s.items {
|
|
||||||
if ownerID == nil || ownerID.Equal(cnr.OwnerID()) {
|
|
||||||
res = append(res, cid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates new container storage
|
|
||||||
// that stores containers in go-builtin map.
|
|
||||||
func New() storage.Storage {
|
|
||||||
return &testStorage{
|
|
||||||
RWMutex: new(sync.RWMutex),
|
|
||||||
items: make(map[container.ID]*container.Container),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Storage conducts testing of container
|
|
||||||
// storage for interface specification.
|
|
||||||
//
|
|
||||||
// Storage must be empty.
|
|
||||||
func Storage(t *testing.T, s storage.Storage) {
|
|
||||||
list, err := s.List(nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Empty(t, list)
|
|
||||||
|
|
||||||
cnr1 := new(container.Container)
|
|
||||||
cnr1.SetOwnerID(container.OwnerID{1, 2, 3})
|
|
||||||
|
|
||||||
id1, err := s.Put(cnr1)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
res, err := s.Get(*id1)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, cnr1, res)
|
|
||||||
|
|
||||||
cnr2 := new(container.Container)
|
|
||||||
owner1 := cnr1.OwnerID()
|
|
||||||
owner1[0]++
|
|
||||||
cnr2.SetOwnerID(owner1)
|
|
||||||
|
|
||||||
id2, err := s.Put(cnr2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
res, err = s.Get(*id2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, cnr2, res)
|
|
||||||
|
|
||||||
list, err = s.List(nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, list, 2)
|
|
||||||
require.Contains(t, list, *id1)
|
|
||||||
require.Contains(t, list, *id2)
|
|
||||||
|
|
||||||
owner1 = cnr1.OwnerID()
|
|
||||||
list, err = s.List(&owner1)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, list, 1)
|
|
||||||
require.Equal(t, *id1, list[0])
|
|
||||||
|
|
||||||
owner2 := cnr2.OwnerID()
|
|
||||||
list, err = s.List(&owner2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, list, 1)
|
|
||||||
require.Equal(t, *id2, list[0])
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNewStorage(t *testing.T) {
|
|
||||||
s := New()
|
|
||||||
|
|
||||||
Storage(t, s)
|
|
||||||
}
|
|
0
pkg/core/netmap/.gitkeep
Normal file
0
pkg/core/netmap/.gitkeep
Normal file
|
@ -1,37 +0,0 @@
|
||||||
package epoch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Size is a size of Epoch
|
|
||||||
// in a binary form.
|
|
||||||
const Size = 8
|
|
||||||
|
|
||||||
// Marshal encodes Epoch into a
|
|
||||||
// binary form and returns the result.
|
|
||||||
//
|
|
||||||
// Result slice has Size length.
|
|
||||||
func Marshal(e Epoch) []byte {
|
|
||||||
d := make([]byte, Size)
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint64(d, ToUint64(e))
|
|
||||||
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBinary unmarshals Epoch from
|
|
||||||
// a binary representation.
|
|
||||||
//
|
|
||||||
// If buffer size is insufficient,
|
|
||||||
// io.ErrUnexpectedEOF is returned.
|
|
||||||
func (e *Epoch) UnmarshalBinary(data []byte) error {
|
|
||||||
if len(data) < Size {
|
|
||||||
return io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
|
|
||||||
*e = FromUint64(binary.BigEndian.Uint64(data))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package epoch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEpochMarshal(t *testing.T) {
|
|
||||||
e := FromUint64(1)
|
|
||||||
e2 := new(Epoch)
|
|
||||||
|
|
||||||
require.NoError(t,
|
|
||||||
e2.UnmarshalBinary(
|
|
||||||
Marshal(e),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
require.True(t, EQ(e, *e2))
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package epoch
|
|
||||||
|
|
||||||
// Sum returns the result of
|
|
||||||
// summing up two Epoch.
|
|
||||||
//
|
|
||||||
// Function defines a binary
|
|
||||||
// operation of summing two Epoch.
|
|
||||||
// Try to avoid using operator
|
|
||||||
// "+" for better portability.
|
|
||||||
func Sum(a, b Epoch) Epoch {
|
|
||||||
return FromUint64(ToUint64(a) + ToUint64(b))
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package epoch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEpochMath(t *testing.T) {
|
|
||||||
items := []struct {
|
|
||||||
mathFn func(Epoch, Epoch) Epoch
|
|
||||||
|
|
||||||
a, b, c uint64
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
mathFn: Sum, a: 1, b: 2, c: 3},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range items {
|
|
||||||
require.Equal(t,
|
|
||||||
item.mathFn(
|
|
||||||
FromUint64(item.a),
|
|
||||||
FromUint64(item.b),
|
|
||||||
),
|
|
||||||
FromUint64(item.c),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package epoch
|
|
||||||
|
|
||||||
// EQ reports whether e and e2 are the same Epoch.
|
|
||||||
//
|
|
||||||
// Function defines the relation of equality
|
|
||||||
// between two Epoch. Try to avoid comparison through
|
|
||||||
// "==" operator for better portability.
|
|
||||||
func EQ(e1, e2 Epoch) bool {
|
|
||||||
return ToUint64(e1) == ToUint64(e2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NE reports whether e1 and e2 are the different Epoch.
|
|
||||||
//
|
|
||||||
// Method defines the relation of inequality
|
|
||||||
// between two Epoch. Try to avoid comparison through
|
|
||||||
// "!=" operator for better portability.
|
|
||||||
func NE(e1, e2 Epoch) bool {
|
|
||||||
return ToUint64(e1) != ToUint64(e2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LT reports whether e1 is less Epoch than e2.
|
|
||||||
//
|
|
||||||
// Method defines the "less than" relation
|
|
||||||
// between two Epoch. Try to avoid comparison through
|
|
||||||
// "<" operator for better portability.
|
|
||||||
func LT(e1, e2 Epoch) bool {
|
|
||||||
return ToUint64(e1) < ToUint64(e2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GT reports whether e1 is greater Epoch than e2.
|
|
||||||
//
|
|
||||||
// Method defines the "greater than" relation
|
|
||||||
// between two Epoch. Try to avoid comparison through
|
|
||||||
// ">" operator for better portability.
|
|
||||||
func GT(e1, e2 Epoch) bool {
|
|
||||||
return ToUint64(e1) > ToUint64(e2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LE reports whether e1 is less or equal Epoch than e2.
|
|
||||||
//
|
|
||||||
// Method defines the "less or equal" relation
|
|
||||||
// between two Epoch. Try to avoid comparison through
|
|
||||||
// "<=" operator for better portability.
|
|
||||||
func LE(e1, e2 Epoch) bool {
|
|
||||||
return ToUint64(e1) <= ToUint64(e2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GE reports whether e1 is greater or equal Epoch than e2.
|
|
||||||
//
|
|
||||||
// Method defines the "greater or equal" relation
|
|
||||||
// between two Epoch. Try to avoid comparison through
|
|
||||||
// ">=" operator for better portability.
|
|
||||||
func GE(e1, e2 Epoch) bool {
|
|
||||||
return ToUint64(e1) >= ToUint64(e2)
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package epoch
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEpochRelations(t *testing.T) {
|
|
||||||
items := []struct {
|
|
||||||
relFn func(Epoch, Epoch) bool
|
|
||||||
|
|
||||||
base, ok, fail uint64
|
|
||||||
}{
|
|
||||||
{relFn: EQ, base: 1, ok: 1, fail: 2},
|
|
||||||
{relFn: NE, base: 1, ok: 2, fail: 1},
|
|
||||||
{relFn: LT, base: 1, ok: 2, fail: 0},
|
|
||||||
{relFn: GT, base: 1, ok: 0, fail: 2},
|
|
||||||
{relFn: LE, base: 1, ok: 1, fail: 0},
|
|
||||||
{relFn: LE, base: 1, ok: 2, fail: 0},
|
|
||||||
{relFn: GE, base: 1, ok: 0, fail: 2},
|
|
||||||
{relFn: GE, base: 1, ok: 1, fail: 2},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range items {
|
|
||||||
require.True(t,
|
|
||||||
item.relFn(
|
|
||||||
FromUint64(item.base),
|
|
||||||
FromUint64(item.ok),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
require.False(t,
|
|
||||||
item.relFn(
|
|
||||||
FromUint64(item.base),
|
|
||||||
FromUint64(item.fail),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package epoch
|
|
||||||
|
|
||||||
// Epoch represents the
|
|
||||||
// number of NeoFS epoch.
|
|
||||||
type Epoch uint64
|
|
||||||
|
|
||||||
// FromUint64 converts builtin
|
|
||||||
// uint64 value to Epoch.
|
|
||||||
//
|
|
||||||
// Try to avoid direct cast for
|
|
||||||
// better portability.
|
|
||||||
func FromUint64(e uint64) Epoch {
|
|
||||||
return Epoch(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToUint64 converts Epoch value
|
|
||||||
// to builtin uint64.
|
|
||||||
//
|
|
||||||
// Try to avoid direct cast for
|
|
||||||
// better portability.
|
|
||||||
func ToUint64(e Epoch) uint64 {
|
|
||||||
return uint64(e)
|
|
||||||
}
|
|
|
@ -1,119 +0,0 @@
|
||||||
package netmap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap/node"
|
|
||||||
"github.com/nspcc-dev/netmap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Info represent node information.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/netmap/node.Info.
|
|
||||||
type Info = node.Info
|
|
||||||
|
|
||||||
// Bucket represents NeoFS network map as a graph.
|
|
||||||
//
|
|
||||||
// If is a type alias of
|
|
||||||
// github.com/nspcc-dev/netmap.Bucket.
|
|
||||||
type Bucket = netmap.Bucket
|
|
||||||
|
|
||||||
// NetMap represents NeoFS network map
|
|
||||||
// with concurrent access support.
|
|
||||||
type NetMap struct {
|
|
||||||
mtx *sync.RWMutex
|
|
||||||
|
|
||||||
root *Bucket
|
|
||||||
|
|
||||||
items []Info
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates and initializes a new NetMap.
|
|
||||||
//
|
|
||||||
// Using the NetMap that has been created with new(NetMap)
|
|
||||||
// expression (or just declaring a NetMap variable) is unsafe
|
|
||||||
// and can lead to panic.
|
|
||||||
func New() *NetMap {
|
|
||||||
return &NetMap{
|
|
||||||
mtx: new(sync.RWMutex),
|
|
||||||
root: new(Bucket),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Root returns the root bucket of the network map.
|
|
||||||
//
|
|
||||||
// Changing the result is unsafe and
|
|
||||||
// affects the network map.
|
|
||||||
func (n NetMap) Root() *Bucket {
|
|
||||||
n.mtx.RLock()
|
|
||||||
defer n.mtx.RUnlock()
|
|
||||||
|
|
||||||
return n.root
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRoot sets the root bucket of the network map.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source bucket
|
|
||||||
// is unsafe and affects the network map.
|
|
||||||
func (n *NetMap) SetRoot(v *Bucket) {
|
|
||||||
n.mtx.Lock()
|
|
||||||
n.root = v
|
|
||||||
n.mtx.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nodes returns node list of the network map.
|
|
||||||
//
|
|
||||||
// Changing the result is unsafe and
|
|
||||||
// affects the network map.
|
|
||||||
func (n NetMap) Nodes() []Info {
|
|
||||||
n.mtx.RLock()
|
|
||||||
defer n.mtx.RUnlock()
|
|
||||||
|
|
||||||
return n.items
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNodes sets node list of the network map.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice
|
|
||||||
// is unsafe and affects the network map.
|
|
||||||
func (n *NetMap) SetNodes(v []Info) {
|
|
||||||
n.mtx.Lock()
|
|
||||||
n.items = v
|
|
||||||
n.mtx.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddNode adds node information to the network map
|
|
||||||
//
|
|
||||||
// If node with provided information is already presented
|
|
||||||
// in network map, nothing happens,
|
|
||||||
func (n *NetMap) AddNode(nodeInfo Info) error {
|
|
||||||
n.mtx.Lock()
|
|
||||||
defer n.mtx.Unlock()
|
|
||||||
|
|
||||||
num := -1
|
|
||||||
|
|
||||||
// looking for existed node info item
|
|
||||||
for i := range n.items {
|
|
||||||
if bytes.Equal(
|
|
||||||
n.items[i].PublicKey(),
|
|
||||||
nodeInfo.PublicKey(),
|
|
||||||
) {
|
|
||||||
num = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add node if it does not exist
|
|
||||||
if num < 0 {
|
|
||||||
n.items = append(n.items, nodeInfo)
|
|
||||||
num = len(n.items) - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.root.AddStrawNode(netmap.Node{
|
|
||||||
N: uint32(num),
|
|
||||||
C: n.items[num].Capacity(),
|
|
||||||
P: n.items[num].Price(),
|
|
||||||
}, nodeInfo.Options()...)
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package netmap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNetMap_Nodes(t *testing.T) {
|
|
||||||
nm := New()
|
|
||||||
|
|
||||||
info1 := Info{}
|
|
||||||
info1.SetPublicKey([]byte{1, 2, 3})
|
|
||||||
|
|
||||||
info2 := Info{}
|
|
||||||
info2.SetPublicKey([]byte{4, 5, 6})
|
|
||||||
|
|
||||||
nodes := []Info{
|
|
||||||
info1,
|
|
||||||
info2,
|
|
||||||
}
|
|
||||||
|
|
||||||
nm.SetNodes(nodes)
|
|
||||||
|
|
||||||
require.Equal(t, nodes, nm.Nodes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNetMap_Root(t *testing.T) {
|
|
||||||
nm := New()
|
|
||||||
|
|
||||||
bucket := &Bucket{
|
|
||||||
Key: "key",
|
|
||||||
Value: "value",
|
|
||||||
}
|
|
||||||
|
|
||||||
nm.SetRoot(bucket)
|
|
||||||
|
|
||||||
require.Equal(t, bucket, nm.Root())
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Info represents the information
|
|
||||||
// about NeoFS storage node.
|
|
||||||
type Info struct {
|
|
||||||
address string // net address
|
|
||||||
|
|
||||||
key []byte // public key
|
|
||||||
|
|
||||||
opts []string // options
|
|
||||||
|
|
||||||
status Status // status bits
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNilInfo is returned by functions that expect
|
|
||||||
// a non-nil Info pointer, but received nil.
|
|
||||||
var ErrNilInfo = errors.New("node info is nil")
|
|
||||||
|
|
||||||
// Address returns node network address.
|
|
||||||
//
|
|
||||||
// Address format is dictated by
|
|
||||||
// application architecture.
|
|
||||||
func (i Info) Address() string {
|
|
||||||
return i.address
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAddress sets node network address.
|
|
||||||
func (i *Info) SetAddress(v string) {
|
|
||||||
i.address = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status returns the node status.
|
|
||||||
func (i Info) Status() Status {
|
|
||||||
return i.status
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetStatus sets the node status.
|
|
||||||
func (i *Info) SetStatus(v Status) {
|
|
||||||
i.status = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicKey returns node public key in
|
|
||||||
// a binary format.
|
|
||||||
//
|
|
||||||
// Changing the result is unsafe and
|
|
||||||
// affects the node info. In order to
|
|
||||||
// prevent state mutations, use
|
|
||||||
// CopyPublicKey.
|
|
||||||
//
|
|
||||||
// Key format is dictated by
|
|
||||||
// application architecture.
|
|
||||||
func (i Info) PublicKey() []byte {
|
|
||||||
return i.key
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyPublicKey returns the copy of
|
|
||||||
// node public key.
|
|
||||||
//
|
|
||||||
// Changing the result is safe and
|
|
||||||
// does not affect the node info.
|
|
||||||
func CopyPublicKey(i Info) []byte {
|
|
||||||
res := make([]byte, len(i.key))
|
|
||||||
|
|
||||||
copy(res, i.key)
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPublicKey sets node public key
|
|
||||||
// in a binary format.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice
|
|
||||||
// is unsafe and affects node info.
|
|
||||||
// In order to prevent state mutations,
|
|
||||||
// use SetPublicKeyCopy.
|
|
||||||
func (i *Info) SetPublicKey(v []byte) {
|
|
||||||
i.key = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPublicKeyCopy copies public key and
|
|
||||||
// sets the copy as node public key.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice
|
|
||||||
// is safe and does not affect node info.
|
|
||||||
//
|
|
||||||
// Returns ErrNilInfo on nil node info.
|
|
||||||
func SetPublicKeyCopy(i *Info, key []byte) error {
|
|
||||||
if i == nil {
|
|
||||||
return ErrNilInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
i.key = make([]byte, len(key))
|
|
||||||
|
|
||||||
copy(i.key, key)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options returns node option list.
|
|
||||||
//
|
|
||||||
// Changing the result is unsafe and
|
|
||||||
// affects the node info. In order to
|
|
||||||
// prevent state mutations, use
|
|
||||||
// CopyOptions.
|
|
||||||
//
|
|
||||||
// Option format is dictated by
|
|
||||||
// application architecture.
|
|
||||||
func (i Info) Options() []string {
|
|
||||||
return i.opts
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyOptions returns the copy of
|
|
||||||
// node options list.
|
|
||||||
//
|
|
||||||
// Changing the result is safe and
|
|
||||||
// does not affect the node info.
|
|
||||||
func CopyOptions(i Info) []string {
|
|
||||||
res := make([]string, len(i.opts))
|
|
||||||
|
|
||||||
copy(res, i.opts)
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOptions sets node option list.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice
|
|
||||||
// is unsafe and affects node info.
|
|
||||||
// In order to prevent state mutations,
|
|
||||||
// use SetOptionsCopy.
|
|
||||||
func (i *Info) SetOptions(v []string) {
|
|
||||||
i.opts = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOptionsCopy copies option list and sets
|
|
||||||
// the copy as node options list.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice
|
|
||||||
// is safe and does not affect node info.
|
|
||||||
//
|
|
||||||
// SetOptionsCopy does nothing if Info is nil.
|
|
||||||
func SetOptionsCopy(i *Info, opts []string) {
|
|
||||||
if i == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
i.opts = make([]string, len(opts))
|
|
||||||
|
|
||||||
copy(i.opts, opts)
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestInfo_Address(t *testing.T) {
|
|
||||||
i := new(Info)
|
|
||||||
|
|
||||||
addr := "address"
|
|
||||||
i.SetAddress(addr)
|
|
||||||
|
|
||||||
require.Equal(t, addr, i.Address())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfo_Status(t *testing.T) {
|
|
||||||
i := new(Info)
|
|
||||||
|
|
||||||
st := StatusFromUint64(1)
|
|
||||||
i.SetStatus(st)
|
|
||||||
|
|
||||||
require.Equal(t, st, i.Status())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfo_PublicKey(t *testing.T) {
|
|
||||||
i := new(Info)
|
|
||||||
|
|
||||||
key := []byte{1, 2, 3}
|
|
||||||
i.SetPublicKey(key)
|
|
||||||
|
|
||||||
require.Equal(t, key, i.PublicKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCopyPublicKey(t *testing.T) {
|
|
||||||
i := Info{}
|
|
||||||
|
|
||||||
// set initial node key
|
|
||||||
initKey := []byte{1, 2, 3}
|
|
||||||
i.SetPublicKey(initKey)
|
|
||||||
|
|
||||||
// get node key copy
|
|
||||||
keyCopy := CopyPublicKey(i)
|
|
||||||
|
|
||||||
// change the copy
|
|
||||||
keyCopy[0]++
|
|
||||||
|
|
||||||
// check that node key has not changed
|
|
||||||
require.Equal(t, initKey, i.PublicKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetPublicKeyCopy(t *testing.T) {
|
|
||||||
require.EqualError(t,
|
|
||||||
SetPublicKeyCopy(nil, nil),
|
|
||||||
ErrNilInfo.Error(),
|
|
||||||
)
|
|
||||||
|
|
||||||
i := new(Info)
|
|
||||||
|
|
||||||
// create source key
|
|
||||||
srcKey := []byte{1, 2, 3}
|
|
||||||
|
|
||||||
// copy and set node key
|
|
||||||
require.NoError(t, SetPublicKeyCopy(i, srcKey))
|
|
||||||
|
|
||||||
// get node key
|
|
||||||
nodeKey := i.PublicKey()
|
|
||||||
|
|
||||||
// change the source key
|
|
||||||
srcKey[0]++
|
|
||||||
|
|
||||||
// check that node key has not changed
|
|
||||||
require.Equal(t, nodeKey, i.PublicKey())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInfo_Options(t *testing.T) {
|
|
||||||
i := new(Info)
|
|
||||||
|
|
||||||
opts := []string{
|
|
||||||
"opt1",
|
|
||||||
"opt2",
|
|
||||||
}
|
|
||||||
i.SetOptions(opts)
|
|
||||||
|
|
||||||
require.Equal(t, opts, i.Options())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCopyOptions(t *testing.T) {
|
|
||||||
i := Info{}
|
|
||||||
|
|
||||||
// set initial node options
|
|
||||||
initOpts := []string{
|
|
||||||
"opt1",
|
|
||||||
"opt2",
|
|
||||||
}
|
|
||||||
i.SetOptions(initOpts)
|
|
||||||
|
|
||||||
// get node options copy
|
|
||||||
optsCopy := CopyOptions(i)
|
|
||||||
|
|
||||||
// change the copy
|
|
||||||
optsCopy[0] = "some other opt"
|
|
||||||
|
|
||||||
// check that node options have not changed
|
|
||||||
require.Equal(t, initOpts, i.Options())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetOptionsCopy(t *testing.T) {
|
|
||||||
require.NotPanics(t, func() {
|
|
||||||
SetOptionsCopy(nil, nil)
|
|
||||||
})
|
|
||||||
|
|
||||||
i := new(Info)
|
|
||||||
|
|
||||||
// create source options
|
|
||||||
srcOpts := []string{
|
|
||||||
"opt1",
|
|
||||||
"opt2",
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy and set node options
|
|
||||||
SetOptionsCopy(i, srcOpts)
|
|
||||||
|
|
||||||
// get node options
|
|
||||||
nodeOpts := i.Options()
|
|
||||||
|
|
||||||
// change the source options
|
|
||||||
srcOpts[0] = "some other opt"
|
|
||||||
|
|
||||||
// check that node options have not changed
|
|
||||||
require.Equal(t, nodeOpts, i.Options())
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/object"
|
|
||||||
)
|
|
||||||
|
|
||||||
const optionPrice = "/Price:"
|
|
||||||
|
|
||||||
const optionCapacity = "/Capacity:"
|
|
||||||
|
|
||||||
// Price parses node options and returns the price in 1e-8*GAS/Megabyte per month.
|
|
||||||
//
|
|
||||||
// User sets the price in GAS/Terabyte per month.
|
|
||||||
func (i Info) Price() uint64 {
|
|
||||||
for j := range i.opts {
|
|
||||||
if strings.HasPrefix(i.opts[j], optionPrice) {
|
|
||||||
n, err := strconv.ParseFloat(i.opts[j][len(optionPrice):], 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return uint64(n*1e8) / uint64(object.UnitsMB) // UnitsMB == megabytes in 1 terabyte
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capacity parses node options and returns the capacity .
|
|
||||||
func (i Info) Capacity() uint64 {
|
|
||||||
for j := range i.opts {
|
|
||||||
if strings.HasPrefix(i.opts[j], optionCapacity) {
|
|
||||||
n, err := strconv.ParseUint(i.opts[j][len(optionCapacity):], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/object"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestInfo_Price(t *testing.T) {
|
|
||||||
var info Info
|
|
||||||
|
|
||||||
// too small value
|
|
||||||
info.opts = []string{"/Price:0.01048575"}
|
|
||||||
require.Equal(t, uint64(0), info.Price())
|
|
||||||
|
|
||||||
// min value
|
|
||||||
info.opts = []string{"/Price:0.01048576"}
|
|
||||||
require.Equal(t, uint64(1), info.Price())
|
|
||||||
|
|
||||||
// big value
|
|
||||||
info.opts = []string{"/Price:1000000000.666"}
|
|
||||||
require.Equal(t, uint64(1000000000.666*1e8/object.UnitsMB), info.Price())
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
// Status represents a node
|
|
||||||
// status bits.
|
|
||||||
type Status uint64
|
|
||||||
|
|
||||||
const leftBitPos = 64
|
|
||||||
|
|
||||||
const (
|
|
||||||
bitFullStorage = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// returns true if n-th left bit is set (starting at 0).
|
|
||||||
func isLeftBitSet(value Status, n uint8) bool {
|
|
||||||
bitMask := Status(1 << (leftBitPos - n))
|
|
||||||
return bitMask != 0 && value&bitMask == bitMask
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets n-th left bit (starting at 0).
|
|
||||||
func setLeftBit(value *Status, n uint8) {
|
|
||||||
*value |= Status(1 << (leftBitPos - n))
|
|
||||||
}
|
|
||||||
|
|
||||||
// resets n-th left bit (starting at 0).
|
|
||||||
func resetLeftBit(value *Status, n uint8) {
|
|
||||||
*value &= ^Status(1 << (leftBitPos - n))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Full returns true if node is in Full status.
|
|
||||||
//
|
|
||||||
// Full status marks node has enough space
|
|
||||||
// for storing users objects.
|
|
||||||
func (n Status) Full() bool {
|
|
||||||
return isLeftBitSet(n, bitFullStorage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFull sets Full status of node.
|
|
||||||
func (n *Status) SetFull() {
|
|
||||||
setLeftBit(n, bitFullStorage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetFull resets Full status of node.
|
|
||||||
func (n *Status) ResetFull() {
|
|
||||||
resetLeftBit(n, bitFullStorage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StatusFromUint64 converts builtin
|
|
||||||
// uint64 value to Status.
|
|
||||||
//
|
|
||||||
// Try to avoid direct cast for
|
|
||||||
// better portability.
|
|
||||||
func StatusFromUint64(v uint64) Status {
|
|
||||||
return Status(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StatusToUint64 converts Status value
|
|
||||||
// to builtin uint64.
|
|
||||||
//
|
|
||||||
// Try to avoid direct cast for
|
|
||||||
// better portability.
|
|
||||||
func StatusToUint64(s Status) uint64 {
|
|
||||||
return uint64(s)
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package node
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStatus_Full(t *testing.T) {
|
|
||||||
st := new(Status)
|
|
||||||
|
|
||||||
st.SetFull()
|
|
||||||
require.True(t, st.Full())
|
|
||||||
|
|
||||||
st.ResetFull()
|
|
||||||
require.False(t, st.Full())
|
|
||||||
}
|
|
0
pkg/core/object/.gitkeep
Normal file
0
pkg/core/object/.gitkeep
Normal file
|
@ -1,94 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
// ExtendedHeaderType represents the enumeration
|
|
||||||
// of extended header types of the NeoFS object.
|
|
||||||
type ExtendedHeaderType uint32
|
|
||||||
|
|
||||||
// ExtendedHeader represents the extended
|
|
||||||
// header of NeoFS object.
|
|
||||||
type ExtendedHeader struct {
|
|
||||||
typ ExtendedHeaderType
|
|
||||||
|
|
||||||
val interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the extended header type.
|
|
||||||
func (h ExtendedHeader) Type() ExtendedHeaderType {
|
|
||||||
return h.typ
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetType sets the extended header type.
|
|
||||||
func (h *ExtendedHeader) SetType(v ExtendedHeaderType) {
|
|
||||||
h.typ = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the extended header value.
|
|
||||||
//
|
|
||||||
// In the case of a reference type, the value is
|
|
||||||
// returned by reference, so value mutations affect
|
|
||||||
// header state. Therefore, callers must first copy
|
|
||||||
// the value before changing manipulations.
|
|
||||||
func (h ExtendedHeader) Value() interface{} {
|
|
||||||
return h.val
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetValue sets the extended header value.
|
|
||||||
//
|
|
||||||
// Caller must take into account that each type of
|
|
||||||
// header usually has a limited set of expected
|
|
||||||
// value types.
|
|
||||||
//
|
|
||||||
// In the case of a reference type, the value is set
|
|
||||||
// by reference, so source value mutations affect
|
|
||||||
// header state. Therefore, callers must first copy
|
|
||||||
// the source value before changing manipulations.
|
|
||||||
func (h *ExtendedHeader) SetValue(v interface{}) {
|
|
||||||
h.val = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeFromUint32 converts builtin
|
|
||||||
// uint32 value to Epoch.
|
|
||||||
//
|
|
||||||
// Try to avoid direct cast for
|
|
||||||
// better portability.
|
|
||||||
func TypeFromUint32(v uint32) ExtendedHeaderType {
|
|
||||||
return ExtendedHeaderType(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeToUint32 converts Epoch value
|
|
||||||
// to builtin uint32.
|
|
||||||
//
|
|
||||||
// Try to avoid direct cast for
|
|
||||||
// better portability.
|
|
||||||
func TypeToUint32(v ExtendedHeaderType) uint32 {
|
|
||||||
return uint32(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypesEQ reports whether t1 and t2 are the same ExtendedHeaderType.
|
|
||||||
//
|
|
||||||
// Function defines the relation of equality
|
|
||||||
// between two ExtendedHeaderType. Try to avoid comparison through
|
|
||||||
// "==" operator for better portability.
|
|
||||||
func TypesEQ(t1, t2 ExtendedHeaderType) bool {
|
|
||||||
return TypeToUint32(t1) == TypeToUint32(t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypesLT reports whether t1 ExtendedHeaderType
|
|
||||||
// is less than t2.
|
|
||||||
//
|
|
||||||
// Function defines the "less than" relation
|
|
||||||
// between two ExtendedHeaderType. Try to avoid
|
|
||||||
// comparison through "<" operator for better portability.
|
|
||||||
func TypesLT(t1, t2 ExtendedHeaderType) bool {
|
|
||||||
return TypeToUint32(t1) < TypeToUint32(t2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypesGT reports whether t1 ExtendedHeaderType
|
|
||||||
// is greater than t2.
|
|
||||||
//
|
|
||||||
// Function defines the "greater than" relation
|
|
||||||
// between two ExtendedHeaderType. Try to avoid
|
|
||||||
// comparison through ">" operator for better portability.
|
|
||||||
func TypesGT(t1, t2 ExtendedHeaderType) bool {
|
|
||||||
return TypeToUint32(t1) > TypeToUint32(t2)
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestExtendedHeader_Type(t *testing.T) {
|
|
||||||
h := new(ExtendedHeader)
|
|
||||||
|
|
||||||
ht := TypeFromUint32(3)
|
|
||||||
h.SetType(ht)
|
|
||||||
|
|
||||||
require.True(t, TypesEQ(ht, h.Type()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtendedHeader_Value(t *testing.T) {
|
|
||||||
h := new(ExtendedHeader)
|
|
||||||
|
|
||||||
val := 100
|
|
||||||
h.SetValue(val)
|
|
||||||
|
|
||||||
require.Equal(t, val, h.Value())
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Header represents NeoFS object header.
|
|
||||||
type Header struct {
|
|
||||||
// SystemHeader is an obligatory part of any object header.
|
|
||||||
// It is used to set the identity and basic parameters of
|
|
||||||
// the object.
|
|
||||||
//
|
|
||||||
// Header must inherit all the methods of SystemHeader,
|
|
||||||
// so the SystemHeader is embedded in Header.
|
|
||||||
SystemHeader
|
|
||||||
|
|
||||||
extendedHeaders []ExtendedHeader // extended headers
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNilHeader is returned by functions that expect
|
|
||||||
// a non-nil Header pointer, but received nil.
|
|
||||||
var ErrNilHeader = errors.New("object header is nil")
|
|
||||||
|
|
||||||
// ExtendedHeaders returns the extended headers of header.
|
|
||||||
//
|
|
||||||
// Changing the result is unsafe and affects the header.
|
|
||||||
// In order to prevent state mutations, use CopyExtendedHeaders.
|
|
||||||
func (h *Header) ExtendedHeaders() []ExtendedHeader {
|
|
||||||
return h.extendedHeaders
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyExtendedHeaders returns the copy of extended headers.
|
|
||||||
//
|
|
||||||
// Changing the result is safe and does not affect the header.
|
|
||||||
//
|
|
||||||
// Returns nil if header is nil.
|
|
||||||
func CopyExtendedHeaders(h *Header) []ExtendedHeader {
|
|
||||||
if h == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]ExtendedHeader, len(h.extendedHeaders))
|
|
||||||
|
|
||||||
copy(res, h.extendedHeaders)
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetExtendedHeaders sets the extended headers of the header.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice is unsafe and affects
|
|
||||||
// the header. In order to prevent state mutations, use
|
|
||||||
// SetExtendedHeadersCopy.
|
|
||||||
func (h *Header) SetExtendedHeaders(v []ExtendedHeader) {
|
|
||||||
h.extendedHeaders = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetExtendedHeadersCopy copies extended headers and sets the copy
|
|
||||||
// as the object extended headers.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice is safe and does not affect
|
|
||||||
// the header.
|
|
||||||
//
|
|
||||||
// SetExtendedHeadersCopy does nothing if Header is nil.
|
|
||||||
func SetExtendedHeadersCopy(h *Header, hs []ExtendedHeader) {
|
|
||||||
if h == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.extendedHeaders = make([]ExtendedHeader, len(hs))
|
|
||||||
|
|
||||||
copy(h.extendedHeaders, hs)
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func testHeaders(num uint32) []ExtendedHeader {
|
|
||||||
res := make([]ExtendedHeader, num)
|
|
||||||
|
|
||||||
for i := uint32(0); i < num; i++ {
|
|
||||||
res[i].SetType(TypeFromUint32(i))
|
|
||||||
res[i].SetValue(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestObject_ExtendedHeaders(t *testing.T) {
|
|
||||||
h := new(Header)
|
|
||||||
|
|
||||||
hs := testHeaders(2)
|
|
||||||
|
|
||||||
h.SetExtendedHeaders(hs)
|
|
||||||
|
|
||||||
require.Equal(t, hs, h.ExtendedHeaders())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCopyExtendedHeaders(t *testing.T) {
|
|
||||||
require.Nil(t, CopyExtendedHeaders(nil))
|
|
||||||
|
|
||||||
h := new(Header)
|
|
||||||
|
|
||||||
// set initial headers
|
|
||||||
initHs := testHeaders(2)
|
|
||||||
h.SetExtendedHeaders(initHs)
|
|
||||||
|
|
||||||
// get extended headers copy
|
|
||||||
hsCopy := CopyExtendedHeaders(h)
|
|
||||||
|
|
||||||
// change the copy
|
|
||||||
hsCopy[0] = hsCopy[1]
|
|
||||||
|
|
||||||
// check that extended headers have not changed
|
|
||||||
require.Equal(t, initHs, h.ExtendedHeaders())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetExtendedHeadersCopy(t *testing.T) {
|
|
||||||
require.NotPanics(t, func() {
|
|
||||||
SetExtendedHeadersCopy(nil, nil)
|
|
||||||
})
|
|
||||||
|
|
||||||
h := new(Header)
|
|
||||||
|
|
||||||
// create source headers
|
|
||||||
srcHs := testHeaders(2)
|
|
||||||
|
|
||||||
// copy and set headers
|
|
||||||
SetExtendedHeadersCopy(h, srcHs)
|
|
||||||
|
|
||||||
// get extended headers
|
|
||||||
objHs := h.ExtendedHeaders()
|
|
||||||
|
|
||||||
// change the source headers
|
|
||||||
srcHs[0] = srcHs[1]
|
|
||||||
|
|
||||||
// check that headeres have not changed
|
|
||||||
require.Equal(t, objHs, h.ExtendedHeaders())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHeaderRelations(t *testing.T) {
|
|
||||||
items := []struct {
|
|
||||||
relFn func(ExtendedHeaderType, ExtendedHeaderType) bool
|
|
||||||
|
|
||||||
base, ok, fail uint32
|
|
||||||
}{
|
|
||||||
{relFn: TypesEQ, base: 1, ok: 1, fail: 2},
|
|
||||||
{relFn: TypesLT, base: 1, ok: 2, fail: 0},
|
|
||||||
{relFn: TypesGT, base: 1, ok: 0, fail: 2},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range items {
|
|
||||||
require.True(t,
|
|
||||||
item.relFn(
|
|
||||||
TypeFromUint32(item.base),
|
|
||||||
TypeFromUint32(item.ok),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
require.False(t,
|
|
||||||
item.relFn(
|
|
||||||
TypeFromUint32(item.base),
|
|
||||||
TypeFromUint32(item.fail),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package headers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Header represents object extended header.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/object.ExtendedHeader.
|
|
||||||
type Header = object.ExtendedHeader
|
|
||||||
|
|
||||||
// Type represents extended header type.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/object.ExtendedHeaderType.
|
|
||||||
type Type = object.ExtendedHeaderType
|
|
||||||
|
|
||||||
const (
|
|
||||||
// this is the only place where this cast is appropriate,
|
|
||||||
// use object.TypeFromUint32 instead.
|
|
||||||
lowerUndefined = Type(iota) // lower unsupported Type value
|
|
||||||
|
|
||||||
// TypeLink is the type of object reference header.
|
|
||||||
TypeLink
|
|
||||||
|
|
||||||
// TypeUser is the of user key-value string header.
|
|
||||||
TypeUser
|
|
||||||
|
|
||||||
// TypeTransform is the type of transformation mark header.
|
|
||||||
TypeTransform
|
|
||||||
|
|
||||||
// TypeTombstone is the type of tombstone mark header.
|
|
||||||
TypeTombstone
|
|
||||||
|
|
||||||
// TypeSessionToken is the type of session token header.
|
|
||||||
TypeSessionToken
|
|
||||||
|
|
||||||
// TypeHomomorphicHash is the type of homomorphic hash header.
|
|
||||||
TypeHomomorphicHash
|
|
||||||
|
|
||||||
// TypePayloadChecksum is the type of payload checksum header.
|
|
||||||
TypePayloadChecksum
|
|
||||||
|
|
||||||
// TypeIntegrity is the type of integrity header.
|
|
||||||
TypeIntegrity
|
|
||||||
|
|
||||||
// TypeStorageGroup is the type of storage group header.
|
|
||||||
TypeStorageGroup
|
|
||||||
|
|
||||||
// TypePublicKey is the type of public key header.
|
|
||||||
TypePublicKey
|
|
||||||
|
|
||||||
upperUndefined // upper unsupported Type value
|
|
||||||
)
|
|
||||||
|
|
||||||
// SupportedType returns true if Type is
|
|
||||||
// the known type of extended header. Each
|
|
||||||
// supported type has named constant.
|
|
||||||
func SupportedType(t Type) bool {
|
|
||||||
return object.TypesGT(t, lowerUndefined) &&
|
|
||||||
object.TypesLT(t, upperUndefined)
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package headers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSupportedType(t *testing.T) {
|
|
||||||
for _, typ := range []Type{
|
|
||||||
TypeLink,
|
|
||||||
TypeUser,
|
|
||||||
TypeTransform,
|
|
||||||
TypeTombstone,
|
|
||||||
TypeSessionToken,
|
|
||||||
TypeHomomorphicHash,
|
|
||||||
TypePayloadChecksum,
|
|
||||||
TypeIntegrity,
|
|
||||||
TypeStorageGroup,
|
|
||||||
TypePublicKey,
|
|
||||||
} {
|
|
||||||
require.True(t, SupportedType(typ))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, typ := range []Type{
|
|
||||||
lowerUndefined,
|
|
||||||
upperUndefined,
|
|
||||||
object.TypeFromUint32(object.TypeToUint32(lowerUndefined) - 1),
|
|
||||||
object.TypeFromUint32(object.TypeToUint32(upperUndefined) + 1),
|
|
||||||
} {
|
|
||||||
require.False(t, SupportedType(typ))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package headers
|
|
||||||
|
|
||||||
// UserHeader is a value of object extended header
|
|
||||||
// that carries user string key-value pairs.
|
|
||||||
//
|
|
||||||
// All user headers must be type of TypeUser.
|
|
||||||
// All user header must have UserHeader pointer value.
|
|
||||||
type UserHeader struct {
|
|
||||||
key, val string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUserHeader creates, initialized and returns
|
|
||||||
// the user extended header.
|
|
||||||
func NewUserHeader(key, val string) *Header {
|
|
||||||
res := new(Header)
|
|
||||||
|
|
||||||
res.SetType(TypeUser)
|
|
||||||
|
|
||||||
res.SetValue(&UserHeader{
|
|
||||||
key: key,
|
|
||||||
val: val,
|
|
||||||
})
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key returns the user header key.
|
|
||||||
func (u UserHeader) Key() string {
|
|
||||||
return u.key
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetKey sets the user header key.
|
|
||||||
func (u *UserHeader) SetKey(key string) {
|
|
||||||
u.key = key
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the user header value.
|
|
||||||
func (u UserHeader) Value() string {
|
|
||||||
return u.val
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetValue sets the user header value.
|
|
||||||
func (u *UserHeader) SetValue(val string) {
|
|
||||||
u.val = val
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package headers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUserHeader_Key(t *testing.T) {
|
|
||||||
h := new(UserHeader)
|
|
||||||
|
|
||||||
key := "random key"
|
|
||||||
h.SetKey(key)
|
|
||||||
|
|
||||||
require.Equal(t, key, h.Key())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserHeader_Value(t *testing.T) {
|
|
||||||
h := new(UserHeader)
|
|
||||||
|
|
||||||
val := "random value"
|
|
||||||
h.SetValue(val)
|
|
||||||
|
|
||||||
require.Equal(t, val, h.Value())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewUserHeader(t *testing.T) {
|
|
||||||
key := "user key"
|
|
||||||
val := "user val"
|
|
||||||
|
|
||||||
h := NewUserHeader(key, val)
|
|
||||||
|
|
||||||
require.True(t,
|
|
||||||
object.TypesEQ(
|
|
||||||
TypeUser,
|
|
||||||
h.Type(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
uh := h.Value().(*UserHeader)
|
|
||||||
|
|
||||||
require.Equal(t, key, uh.Key())
|
|
||||||
require.Equal(t, val, uh.Value())
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ID represents the object identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-api-go/refs.ObjectID.
|
|
||||||
// FIXME: object ID should be defined in core package.
|
|
||||||
type ID = refs.ObjectID
|
|
||||||
|
|
||||||
// Address represents NeoFS Object address.
|
|
||||||
// Acts as a reference to the object.
|
|
||||||
type Address struct {
|
|
||||||
cid CID
|
|
||||||
|
|
||||||
id ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// CID return the identifier of the container
|
|
||||||
// that the object belongs to.
|
|
||||||
func (a Address) CID() CID {
|
|
||||||
return a.cid
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCID sets the identifier of the container
|
|
||||||
// that the object belongs to.
|
|
||||||
func (a *Address) SetCID(v CID) {
|
|
||||||
a.cid = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID returns the unique identifier of the
|
|
||||||
// object in container.
|
|
||||||
func (a Address) ID() ID {
|
|
||||||
return a.id
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetID sets the unique identifier of the
|
|
||||||
// object in container.
|
|
||||||
func (a *Address) SetID(v ID) {
|
|
||||||
a.id = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddressFromObject returns an address based
|
|
||||||
// on the object's header.
|
|
||||||
//
|
|
||||||
// Returns nil on nil object.
|
|
||||||
func AddressFromObject(o *Object) *Address {
|
|
||||||
if o == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
a := new(Address)
|
|
||||||
|
|
||||||
a.SetCID(o.CID())
|
|
||||||
a.SetID(o.ID())
|
|
||||||
|
|
||||||
return a
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAddress_CID(t *testing.T) {
|
|
||||||
a := new(Address)
|
|
||||||
|
|
||||||
cid := CID{1, 2, 3}
|
|
||||||
a.SetCID(cid)
|
|
||||||
|
|
||||||
require.Equal(t, cid, a.CID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddress_ID(t *testing.T) {
|
|
||||||
a := new(Address)
|
|
||||||
|
|
||||||
id := ID{1, 2, 3}
|
|
||||||
a.SetID(id)
|
|
||||||
|
|
||||||
require.Equal(t, id, a.ID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddressFromObject(t *testing.T) {
|
|
||||||
require.Nil(t, AddressFromObject(nil))
|
|
||||||
|
|
||||||
o := new(Object)
|
|
||||||
|
|
||||||
cid := CID{4, 5, 6}
|
|
||||||
o.SetCID(cid)
|
|
||||||
|
|
||||||
id := ID{1, 2, 3}
|
|
||||||
o.SetID(id)
|
|
||||||
|
|
||||||
a := AddressFromObject(o)
|
|
||||||
|
|
||||||
require.Equal(t, cid, a.CID())
|
|
||||||
require.Equal(t, id, a.ID())
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Object represents NeoFS Object.
|
|
||||||
type Object struct {
|
|
||||||
// Header is an obligatory part of any object.
|
|
||||||
// It is used to carry any additional information
|
|
||||||
// besides payload.
|
|
||||||
//
|
|
||||||
// Object must inherit all the methods of Header,
|
|
||||||
// so the Header is embedded in Object.
|
|
||||||
Header
|
|
||||||
|
|
||||||
payload []byte // payload bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNilObject is returned by functions that expect
|
|
||||||
// a non-nil Object pointer, but received nil.
|
|
||||||
var ErrNilObject = errors.New("object is nil")
|
|
||||||
|
|
||||||
// Payload returns payload bytes of the object.
|
|
||||||
//
|
|
||||||
// Changing the result is unsafe and affects
|
|
||||||
// the object. In order to prevent state
|
|
||||||
// mutations, use CopyPayload.
|
|
||||||
func (o *Object) Payload() []byte {
|
|
||||||
return o.payload
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyPayload returns the copy of
|
|
||||||
// object payload.
|
|
||||||
//
|
|
||||||
// Changing the result is safe and
|
|
||||||
// does not affect the object.
|
|
||||||
//
|
|
||||||
// CopyPayload returns nil if object is nil.
|
|
||||||
func CopyPayload(o *Object) []byte {
|
|
||||||
if o == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
res := make([]byte, len(o.payload))
|
|
||||||
copy(res, o.payload)
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPayload sets objecyt payload bytes.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice
|
|
||||||
// is unsafe and affects the object.
|
|
||||||
// In order to prevent state mutations,
|
|
||||||
// use SetPayloadCopy.
|
|
||||||
func (o *Object) SetPayload(v []byte) {
|
|
||||||
o.payload = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPayloadCopy copies slice bytes and sets
|
|
||||||
// the copy as object payload.
|
|
||||||
//
|
|
||||||
// Subsequent changing the source slice
|
|
||||||
// is safe and does not affect the object.
|
|
||||||
//
|
|
||||||
// SetPayloadCopy does nothing if object is nil.
|
|
||||||
func SetPayloadCopy(o *Object, payload []byte) {
|
|
||||||
if o == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
o.payload = make([]byte, len(payload))
|
|
||||||
|
|
||||||
copy(o.payload, payload)
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestObject_Payload(t *testing.T) {
|
|
||||||
o := new(Object)
|
|
||||||
|
|
||||||
payload := []byte{1, 2, 3}
|
|
||||||
o.SetPayload(payload)
|
|
||||||
|
|
||||||
require.Equal(t, payload, o.Payload())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCopyPayload(t *testing.T) {
|
|
||||||
require.Nil(t, CopyPayload(nil))
|
|
||||||
|
|
||||||
o := new(Object)
|
|
||||||
|
|
||||||
// set initial node key
|
|
||||||
initPayload := []byte{1, 2, 3}
|
|
||||||
o.SetPayload(initPayload)
|
|
||||||
|
|
||||||
// get payload copy
|
|
||||||
pCopy := CopyPayload(o)
|
|
||||||
|
|
||||||
// change the copy
|
|
||||||
pCopy[0]++
|
|
||||||
|
|
||||||
// check that payload has not changed
|
|
||||||
require.Equal(t, initPayload, o.Payload())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSetPayloadCopy(t *testing.T) {
|
|
||||||
require.NotPanics(t, func() {
|
|
||||||
SetExtendedHeadersCopy(nil, nil)
|
|
||||||
})
|
|
||||||
|
|
||||||
o := new(Object)
|
|
||||||
|
|
||||||
// create source payload
|
|
||||||
srcPayload := []byte{1, 2, 3}
|
|
||||||
|
|
||||||
// copy and set payload
|
|
||||||
SetPayloadCopy(o, srcPayload)
|
|
||||||
|
|
||||||
// get payload
|
|
||||||
objPayload := o.Payload()
|
|
||||||
|
|
||||||
// change the source payload
|
|
||||||
srcPayload[0]++
|
|
||||||
|
|
||||||
// check that payload has not changed
|
|
||||||
require.Equal(t, objPayload, o.Payload())
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Object represents the NeoFS Object.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/object.Object.
|
|
||||||
type Object = object.Object
|
|
||||||
|
|
||||||
// Address represents the address of
|
|
||||||
// NeoFS Object.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/object.Address.
|
|
||||||
type Address = object.Address
|
|
||||||
|
|
||||||
// Storage is an interface that wraps
|
|
||||||
// basic object storage methods.
|
|
||||||
type Storage interface {
|
|
||||||
// Put saves pointed object to the underlying storage.
|
|
||||||
// It returns object address for reference and any error
|
|
||||||
// encountered that caused the saving to interrupt.
|
|
||||||
//
|
|
||||||
// Put must return object.ErrNilObject on nil-pointer.
|
|
||||||
//
|
|
||||||
// Implementations must not modify the object through the pointer (even temporarily).
|
|
||||||
// Implementations must not retain the object pointer.
|
|
||||||
//
|
|
||||||
// Object rewriting behavior is dictated by implementation.
|
|
||||||
Put(*Object) (*Address, error)
|
|
||||||
|
|
||||||
// Get reads the object from the storage by address.
|
|
||||||
// It returns the pointer to requested object and any error encountered.
|
|
||||||
//
|
|
||||||
// Get must return exactly one non-nil value.
|
|
||||||
// Get must return ErrNotFound if the object is not in storage.
|
|
||||||
//
|
|
||||||
// Implementations must not retain the object pointer and modify
|
|
||||||
// the object through it.
|
|
||||||
Get(Address) (*Object, error)
|
|
||||||
|
|
||||||
// Delete removes the object from the storage.
|
|
||||||
// It returns any error encountered that caused the deletion to interrupt.
|
|
||||||
//
|
|
||||||
// Delete must return nil if object was successfully deleted.
|
|
||||||
//
|
|
||||||
// Behavior when deleting a nonexistent object is dictated by implementation.
|
|
||||||
Delete(Address) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNotFound is the error returned when object was not found in storage.
|
|
||||||
var ErrNotFound = errors.New("object not found")
|
|
||||||
|
|
||||||
// ErrNilStorage is the error returned by functions that
|
|
||||||
// expect a non-nil object storage implementation, but received nil.
|
|
||||||
var ErrNilStorage = errors.New("object storage is nil")
|
|
|
@ -1,88 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/object/storage"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testStorage struct {
|
|
||||||
*sync.RWMutex
|
|
||||||
|
|
||||||
items map[storage.Address]*storage.Object
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) Put(o *storage.Object) (*storage.Address, error) {
|
|
||||||
if o == nil {
|
|
||||||
return nil, object.ErrNilObject
|
|
||||||
}
|
|
||||||
|
|
||||||
a := object.AddressFromObject(o)
|
|
||||||
|
|
||||||
s.Lock()
|
|
||||||
s.items[*a] = o
|
|
||||||
s.Unlock()
|
|
||||||
|
|
||||||
return a, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) Get(a storage.Address) (*storage.Object, error) {
|
|
||||||
s.RLock()
|
|
||||||
o, ok := s.items[a]
|
|
||||||
s.RUnlock()
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil, storage.ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
return o, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *testStorage) Delete(a storage.Address) error {
|
|
||||||
s.Lock()
|
|
||||||
delete(s.items, a)
|
|
||||||
s.Unlock()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates new container storage
|
|
||||||
// that stores containers in go-builtin map.
|
|
||||||
func New() storage.Storage {
|
|
||||||
return &testStorage{
|
|
||||||
RWMutex: new(sync.RWMutex),
|
|
||||||
items: make(map[storage.Address]*storage.Object),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Storage conducts testing of object
|
|
||||||
// storage for interface specification.
|
|
||||||
//
|
|
||||||
// Storage must be empty.
|
|
||||||
func Storage(t *testing.T, s storage.Storage) {
|
|
||||||
_, err := s.Put(nil)
|
|
||||||
require.True(t, errors.Is(err, object.ErrNilObject))
|
|
||||||
|
|
||||||
a := new(object.Address)
|
|
||||||
_, err = s.Get(*a)
|
|
||||||
require.True(t, errors.Is(err, storage.ErrNotFound))
|
|
||||||
|
|
||||||
o := new(object.Object)
|
|
||||||
o.SetID(object.ID{1, 2, 3})
|
|
||||||
|
|
||||||
a, err = s.Put(o)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
o2, err := s.Get(*a)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(t, o, o2)
|
|
||||||
|
|
||||||
require.NoError(t, s.Delete(*a))
|
|
||||||
_, err = s.Get(*a)
|
|
||||||
require.True(t, errors.Is(err, storage.ErrNotFound))
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNewStorage(t *testing.T) {
|
|
||||||
s := New()
|
|
||||||
|
|
||||||
Storage(t, s)
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap/epoch"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CID represents the container identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
|
||||||
type CID = container.ID
|
|
||||||
|
|
||||||
// OwnerID represents the container
|
|
||||||
// owner identifier.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.OwnerID.
|
|
||||||
type OwnerID = container.OwnerID
|
|
||||||
|
|
||||||
// Epoch represents the NeoFS epoch number.
|
|
||||||
//
|
|
||||||
// It is a type alias of
|
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/netmap/epoch.Epoch.
|
|
||||||
type Epoch = epoch.Epoch
|
|
||||||
|
|
||||||
// SystemHeader represents the
|
|
||||||
// system header of NeoFS Object.
|
|
||||||
type SystemHeader struct {
|
|
||||||
version uint64 // object version
|
|
||||||
|
|
||||||
payloadLen uint64 // length of the payload bytes
|
|
||||||
|
|
||||||
id ID // object ID
|
|
||||||
|
|
||||||
cid CID // container ID
|
|
||||||
|
|
||||||
ownerID OwnerID // object owner ID
|
|
||||||
|
|
||||||
creatEpoch Epoch // creation epoch number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version returns the object version number.
|
|
||||||
func (s *SystemHeader) Version() uint64 {
|
|
||||||
return s.version
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetVersion sets the object version number.
|
|
||||||
func (s *SystemHeader) SetVersion(v uint64) {
|
|
||||||
s.version = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// PayloadLength returns the length of the
|
|
||||||
// object payload bytes.
|
|
||||||
func (s *SystemHeader) PayloadLength() uint64 {
|
|
||||||
return s.payloadLen
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPayloadLength sets the length of the object
|
|
||||||
// payload bytes.
|
|
||||||
func (s *SystemHeader) SetPayloadLength(v uint64) {
|
|
||||||
s.payloadLen = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID returns the object identifier.
|
|
||||||
func (s *SystemHeader) ID() ID {
|
|
||||||
return s.id
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetID sets the object identifier.
|
|
||||||
func (s *SystemHeader) SetID(v ID) {
|
|
||||||
s.id = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// CID returns the container identifier
|
|
||||||
// to which the object belongs.
|
|
||||||
func (s *SystemHeader) CID() CID {
|
|
||||||
return s.cid
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCID sets the container identifier
|
|
||||||
// to which the object belongs.
|
|
||||||
func (s *SystemHeader) SetCID(v CID) {
|
|
||||||
s.cid = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// OwnerID returns the object owner identifier.
|
|
||||||
func (s *SystemHeader) OwnerID() OwnerID {
|
|
||||||
return s.ownerID
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOwnerID sets the object owner identifier.
|
|
||||||
func (s *SystemHeader) SetOwnerID(v OwnerID) {
|
|
||||||
s.ownerID = v
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreationEpoch returns the epoch number
|
|
||||||
// in which the object was created.
|
|
||||||
func (s *SystemHeader) CreationEpoch() Epoch {
|
|
||||||
return s.creatEpoch
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCreationEpoch sets the epoch number
|
|
||||||
// in which the object was created.
|
|
||||||
func (s *SystemHeader) SetCreationEpoch(v Epoch) {
|
|
||||||
s.creatEpoch = v
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap/epoch"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSystemHeader_Version(t *testing.T) {
|
|
||||||
h := new(SystemHeader)
|
|
||||||
|
|
||||||
v := uint64(7)
|
|
||||||
h.SetVersion(v)
|
|
||||||
|
|
||||||
require.Equal(t, v, h.Version())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSystemHeader_PayloadLength(t *testing.T) {
|
|
||||||
h := new(SystemHeader)
|
|
||||||
|
|
||||||
ln := uint64(3)
|
|
||||||
h.SetPayloadLength(ln)
|
|
||||||
|
|
||||||
require.Equal(t, ln, h.PayloadLength())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSystemHeader_ID(t *testing.T) {
|
|
||||||
h := new(SystemHeader)
|
|
||||||
|
|
||||||
id := ID{1, 2, 3}
|
|
||||||
h.SetID(id)
|
|
||||||
|
|
||||||
require.Equal(t, id, h.ID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSystemHeader_CID(t *testing.T) {
|
|
||||||
h := new(SystemHeader)
|
|
||||||
|
|
||||||
cid := CID{1, 2, 3}
|
|
||||||
h.SetCID(cid)
|
|
||||||
|
|
||||||
require.Equal(t, cid, h.CID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSystemHeader_OwnerID(t *testing.T) {
|
|
||||||
h := new(SystemHeader)
|
|
||||||
|
|
||||||
ownerID := OwnerID{1, 2, 3}
|
|
||||||
h.SetOwnerID(ownerID)
|
|
||||||
|
|
||||||
require.Equal(t, ownerID, h.OwnerID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSystemHeader_CreationEpoch(t *testing.T) {
|
|
||||||
h := new(SystemHeader)
|
|
||||||
|
|
||||||
ep := epoch.FromUint64(1)
|
|
||||||
h.SetCreationEpoch(ep)
|
|
||||||
|
|
||||||
require.True(t, epoch.EQ(ep, h.CreationEpoch()))
|
|
||||||
}
|
|
|
@ -1,35 +1,11 @@
|
||||||
package wrapper
|
package wrapper
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client/balance"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OwnerID represents the container owner identifier.
|
// OwnerID represents the container owner identifier.
|
||||||
//
|
// FIXME: correct the definition.
|
||||||
// It is a type alias of
|
type OwnerID struct{}
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.OwnerID.
|
|
||||||
type OwnerID = container.OwnerID
|
|
||||||
|
|
||||||
// BalanceOf receives the amount of funds in the client's account
|
// BalanceOf receives the amount of funds in the client's account
|
||||||
// through the Balance contract call, and returns it.
|
// through the Balance contract call, and returns it.
|
||||||
func (w *Wrapper) BalanceOf(ownerID OwnerID) (int64, error) {
|
func (w *Wrapper) BalanceOf(ownerID OwnerID) (int64, error) {
|
||||||
// convert Neo wallet address to Uint160
|
panic("implement me")
|
||||||
u160, err := address.StringToUint160(ownerID.String())
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.Wrap(err, "could not convert wallet address to Uint160")
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare invocation arguments
|
|
||||||
args := balance.GetBalanceOfArgs{}
|
|
||||||
args.SetWallet(u160.BytesBE())
|
|
||||||
|
|
||||||
values, err := w.client.BalanceOf(args)
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.Wrap(err, "could not invoke smart contract")
|
|
||||||
}
|
|
||||||
|
|
||||||
return values.Amount(), nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,12 @@
|
||||||
package wrapper
|
package wrapper
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OwnerID represents the container owner identifier.
|
// OwnerID represents the container owner identifier.
|
||||||
//
|
// FIXME: correct the definition.
|
||||||
// It is a type alias of
|
type OwnerID struct{}
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/storage.OwnerID.
|
|
||||||
type OwnerID = storage.OwnerID
|
|
||||||
|
|
||||||
// Container represents the NeoFS Container structure.
|
// Container represents the NeoFS Container structure.
|
||||||
//
|
// FIXME: correct the definition.
|
||||||
// It is a type alias of
|
type Container struct{}
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/storage.Container.
|
|
||||||
type Container = storage.Container
|
|
||||||
|
|
||||||
// Put saves passed container structure in NeoFS system
|
// Put saves passed container structure in NeoFS system
|
||||||
// through Container contract call.
|
// through Container contract call.
|
||||||
|
@ -26,33 +14,7 @@ type Container = storage.Container
|
||||||
// Returns calculated container identifier and any error
|
// Returns calculated container identifier and any error
|
||||||
// encountered that caused the saving to interrupt.
|
// encountered that caused the saving to interrupt.
|
||||||
func (w *Wrapper) Put(cnr *Container) (*CID, error) {
|
func (w *Wrapper) Put(cnr *Container) (*CID, error) {
|
||||||
// calculate container identifier
|
panic("implement me")
|
||||||
//
|
|
||||||
// Note: cid is used as return value only, but the calculation is performed
|
|
||||||
// primarily in order to catch potential error before contract client call.
|
|
||||||
cid, err := container.CalculateID(cnr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not calculate container identifier")
|
|
||||||
}
|
|
||||||
|
|
||||||
// marshal the container
|
|
||||||
cnrBytes, err := cnr.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not marshal the container")
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare invocation arguments
|
|
||||||
args := contract.PutArgs{}
|
|
||||||
args.SetOwnerID(cnr.OwnerID().Bytes())
|
|
||||||
args.SetContainer(cnrBytes)
|
|
||||||
args.SetSignature(nil) // TODO: set signature from request when will appear.
|
|
||||||
|
|
||||||
// invoke smart contract call
|
|
||||||
if err := w.client.Put(args); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
|
||||||
}
|
|
||||||
|
|
||||||
return cid, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get reads the container from NeoFS system by identifier
|
// Get reads the container from NeoFS system by identifier
|
||||||
|
@ -61,29 +23,7 @@ func (w *Wrapper) Put(cnr *Container) (*CID, error) {
|
||||||
// If an empty slice is returned for the requested identifier,
|
// If an empty slice is returned for the requested identifier,
|
||||||
// storage.ErrNotFound error is returned.
|
// storage.ErrNotFound error is returned.
|
||||||
func (w *Wrapper) Get(cid CID) (*Container, error) {
|
func (w *Wrapper) Get(cid CID) (*Container, error) {
|
||||||
// prepare invocation arguments
|
panic("implement me")
|
||||||
args := contract.GetArgs{}
|
|
||||||
args.SetCID(cid.Bytes())
|
|
||||||
|
|
||||||
// invoke smart contract call
|
|
||||||
values, err := w.client.Get(args)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
|
||||||
}
|
|
||||||
|
|
||||||
cnrBytes := values.Container()
|
|
||||||
if len(cnrBytes) == 0 {
|
|
||||||
return nil, storage.ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
cnr := new(Container)
|
|
||||||
|
|
||||||
// unmarshal the container
|
|
||||||
if err := cnr.UnmarshalBinary(cnrBytes); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not unmarshal container")
|
|
||||||
}
|
|
||||||
|
|
||||||
return cnr, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes the container from NeoFS system
|
// Delete removes the container from NeoFS system
|
||||||
|
@ -92,19 +32,7 @@ func (w *Wrapper) Get(cid CID) (*Container, error) {
|
||||||
// Returns any error encountered that caused
|
// Returns any error encountered that caused
|
||||||
// the removal to interrupt.
|
// the removal to interrupt.
|
||||||
func (w *Wrapper) Delete(cid CID) error {
|
func (w *Wrapper) Delete(cid CID) error {
|
||||||
// prepare invocation arguments
|
panic("implement me")
|
||||||
args := contract.DeleteArgs{}
|
|
||||||
args.SetCID(cid.Bytes())
|
|
||||||
args.SetOwnerID(nil) // TODO: add owner ID when will appear.
|
|
||||||
args.SetSignature(nil) // TODO: add CID signature when will appear.
|
|
||||||
|
|
||||||
// invoke smart contract call
|
|
||||||
//
|
|
||||||
// Note: errors.Wrap return nil on nil error arg.
|
|
||||||
return errors.Wrap(
|
|
||||||
w.client.Delete(args),
|
|
||||||
"could not invoke smart contract",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// List returns a list of container identifiers belonging
|
// List returns a list of container identifiers belonging
|
||||||
|
@ -114,35 +42,5 @@ func (w *Wrapper) Delete(cid CID) error {
|
||||||
// Returns the identifiers of all NeoFS containers if pointer
|
// Returns the identifiers of all NeoFS containers if pointer
|
||||||
// to owner identifier is nil.
|
// to owner identifier is nil.
|
||||||
func (w *Wrapper) List(ownerID *OwnerID) ([]CID, error) {
|
func (w *Wrapper) List(ownerID *OwnerID) ([]CID, error) {
|
||||||
// prepare invocation arguments
|
panic("implement me")
|
||||||
args := contract.ListArgs{}
|
|
||||||
|
|
||||||
// Note: by default owner identifier slice is nil,
|
|
||||||
// so client won't attach invocation arguments.
|
|
||||||
// This behavior matches the nil argument of current method.
|
|
||||||
// If argument is not nil, we must specify owner identifier.
|
|
||||||
if ownerID != nil {
|
|
||||||
args.SetOwnerID(ownerID.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
// invoke smart contract call
|
|
||||||
values, err := w.client.List(args)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
|
||||||
}
|
|
||||||
|
|
||||||
binCIDList := values.CIDList()
|
|
||||||
cidList := make([]CID, 0, len(binCIDList))
|
|
||||||
|
|
||||||
// unmarshal all container identifiers
|
|
||||||
for i := range binCIDList {
|
|
||||||
cid, err := refs.CIDFromBytes(binCIDList[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "could not decode container ID #%d", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
cidList = append(cidList, cid)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cidList, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,13 @@
|
||||||
package wrapper
|
package wrapper
|
||||||
|
|
||||||
import (
|
|
||||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Table represents extended ACL rule table.
|
// Table represents extended ACL rule table.
|
||||||
//
|
// FIXME: correct the definition.
|
||||||
// It is a type alias of
|
type Table struct{}
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage.Table.
|
|
||||||
type Table = storage.Table
|
|
||||||
|
|
||||||
// GetEACL reads the extended ACL table from NeoFS system
|
// GetEACL reads the extended ACL table from NeoFS system
|
||||||
// through Container contract call.
|
// through Container contract call.
|
||||||
func (w *Wrapper) GetEACL(cid CID) (Table, error) {
|
func (w *Wrapper) GetEACL(cid CID) (Table, error) {
|
||||||
// prepare invocation arguments
|
panic("implement me")
|
||||||
args := contract.EACLArgs{}
|
|
||||||
args.SetCID(cid.Bytes())
|
|
||||||
|
|
||||||
// invoke smart contract call
|
|
||||||
values, err := w.client.EACL(args)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmarshal and return eACL table
|
|
||||||
return eacl.UnmarshalTable(values.EACL())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutEACL saves the extended ACL table in NeoFS system
|
// PutEACL saves the extended ACL table in NeoFS system
|
||||||
|
@ -35,17 +15,5 @@ func (w *Wrapper) GetEACL(cid CID) (Table, error) {
|
||||||
//
|
//
|
||||||
// Returns any error encountered that caused the saving to interrupt.
|
// Returns any error encountered that caused the saving to interrupt.
|
||||||
func (w *Wrapper) PutEACL(cid CID, table Table, sig []byte) error {
|
func (w *Wrapper) PutEACL(cid CID, table Table, sig []byte) error {
|
||||||
// prepare invocation arguments
|
panic("implement me")
|
||||||
args := contract.SetEACLArgs{}
|
|
||||||
args.SetEACL(eacl.MarshalTable(table))
|
|
||||||
args.SetCID(cid.Bytes())
|
|
||||||
args.SetSignature(sig)
|
|
||||||
|
|
||||||
// invoke smart contract call
|
|
||||||
//
|
|
||||||
// Note: errors.Wrap return nil on nil error arg.
|
|
||||||
return errors.Wrap(
|
|
||||||
w.client.SetEACL(args),
|
|
||||||
"could not invoke smart contract",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package wrapper
|
package wrapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,10 +11,8 @@ import (
|
||||||
type Client = container.Client
|
type Client = container.Client
|
||||||
|
|
||||||
// CID represents the container identifier.
|
// CID represents the container identifier.
|
||||||
//
|
// FIXME: correct the definition.
|
||||||
// CID is a type alias of
|
type CID struct{}
|
||||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/storage.CID.
|
|
||||||
type CID = storage.CID
|
|
||||||
|
|
||||||
// Wrapper is a wrapper over container contract
|
// Wrapper is a wrapper over container contract
|
||||||
// client which implements container storage and
|
// client which implements container storage and
|
||||||
|
|
|
@ -1,37 +1,10 @@
|
||||||
package wrapper
|
package wrapper
|
||||||
|
|
||||||
import (
|
// NodeInfo groups information about NeoFS storage node.
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
type NodeInfo struct{}
|
||||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddPeer registers peer in NeoFS network through
|
// AddPeer registers peer in NeoFS network through
|
||||||
// Netmap contract call.
|
// Netmap contract call.
|
||||||
func (w *Wrapper) AddPeer(nodeInfo netmap.Info) error {
|
func (w *Wrapper) AddPeer(nodeInfo NodeInfo) error {
|
||||||
// prepare invocation arguments
|
panic("implement me")
|
||||||
args := contract.AddPeerArgs{}
|
|
||||||
|
|
||||||
info := contract.PeerInfo{}
|
|
||||||
info.SetPublicKey(nodeInfo.PublicKey())
|
|
||||||
info.SetAddress([]byte(nodeInfo.Address()))
|
|
||||||
|
|
||||||
opts := nodeInfo.Options()
|
|
||||||
binOpts := make([][]byte, 0, len(opts))
|
|
||||||
|
|
||||||
for i := range opts {
|
|
||||||
binOpts = append(binOpts, []byte(opts[i]))
|
|
||||||
}
|
|
||||||
|
|
||||||
info.SetOptions(binOpts)
|
|
||||||
|
|
||||||
args.SetInfo(info)
|
|
||||||
|
|
||||||
// invoke smart contract call
|
|
||||||
//
|
|
||||||
// Note: errors.Wrap returns nil on nil error arg.
|
|
||||||
return errors.Wrap(
|
|
||||||
w.client.AddPeer(args),
|
|
||||||
"could not invoke smart contract",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue