From 62154da17c1c77d0ea69cef652c7fd0199d31e20 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Fri, 22 Apr 2022 16:30:20 +0300 Subject: [PATCH] [#1324] services/tree: Implement Object Tree Service Object Tree Service allows changing trees assotiated with the container in runtime. Signed-off-by: Evgenii Stratonikov --- cmd/neofs-node/config/tree/config.go | 39 +++ cmd/neofs-node/config/tree/config_test.go | 30 +++ cmd/neofs-node/main.go | 1 + cmd/neofs-node/tree.go | 41 +++ config/example/node.env | 3 + config/example/node.json | 5 + config/example/node.yaml | 4 + go.mod | 8 + go.sum | Bin 98717 -> 99242 bytes pkg/services/tree/options.go | 59 +++++ pkg/services/tree/replicator.go | 145 +++++++++++ pkg/services/tree/service.go | 294 ++++++++++++++++++++++ pkg/services/tree/service.pb.go | Bin 0 -> 84811 bytes pkg/services/tree/service.proto | 194 ++++++++++++++ pkg/services/tree/service_grpc.pb.go | Bin 0 -> 12685 bytes pkg/services/tree/signature.go | 44 ++++ pkg/services/tree/types.pb.go | Bin 0 -> 9666 bytes pkg/services/tree/types.proto | 27 ++ 18 files changed, 894 insertions(+) create mode 100644 cmd/neofs-node/config/tree/config.go create mode 100644 cmd/neofs-node/config/tree/config_test.go create mode 100644 cmd/neofs-node/tree.go create mode 100644 pkg/services/tree/options.go create mode 100644 pkg/services/tree/replicator.go create mode 100644 pkg/services/tree/service.go create mode 100644 pkg/services/tree/service.pb.go create mode 100644 pkg/services/tree/service.proto create mode 100644 pkg/services/tree/service_grpc.pb.go create mode 100644 pkg/services/tree/signature.go create mode 100644 pkg/services/tree/types.pb.go create mode 100644 pkg/services/tree/types.proto diff --git a/cmd/neofs-node/config/tree/config.go b/cmd/neofs-node/config/tree/config.go new file mode 100644 index 00000000..8fdc1101 --- /dev/null +++ b/cmd/neofs-node/config/tree/config.go @@ -0,0 +1,39 @@ +package treeconfig + +import ( + "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config" +) + +// GRPCConfig is a wrapper over "grpc" config section which provides access +// to gRPC configuration of control service. +type GRPCConfig struct { + cfg *config.Config +} + +const ( + subsection = "tree" + grpcSubsection = "grpc" + + // GRPCEndpointDefault is a default endpoint of gRPC Control service. + GRPCEndpointDefault = "" +) + +// GRPC returns structure that provides access to "grpc" subsection of +// "tree" section. +func GRPC(c *config.Config) GRPCConfig { + return GRPCConfig{ + c.Sub(subsection).Sub(grpcSubsection), + } +} + +// Endpoint returns value of "endpoint" config parameter. +// +// Returns GRPCEndpointDefault if value is not a non-empty string. +func (g GRPCConfig) Endpoint() string { + v := config.String(g.cfg, "endpoint") + if v != "" { + return v + } + + return GRPCEndpointDefault +} diff --git a/cmd/neofs-node/config/tree/config_test.go b/cmd/neofs-node/config/tree/config_test.go new file mode 100644 index 00000000..9ac92fe6 --- /dev/null +++ b/cmd/neofs-node/config/tree/config_test.go @@ -0,0 +1,30 @@ +package treeconfig_test + +import ( + "testing" + + "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config" + configtest "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/test" + treeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/tree" + "github.com/stretchr/testify/require" +) + +func TestControlSection(t *testing.T) { + t.Run("defaults", func(t *testing.T) { + empty := configtest.EmptyConfig() + + require.Equal(t, treeconfig.GRPCEndpointDefault, treeconfig.GRPC(empty).Endpoint()) + }) + + const path = "../../../../config/example/node" + + var fileConfigTest = func(c *config.Config) { + require.Equal(t, "127.0.0.1:8091", treeconfig.GRPC(c).Endpoint()) + } + + configtest.ForEachFileType(path, fileConfigTest) + + t.Run("ENV", func(t *testing.T) { + configtest.ForEnvFileType(path, fileConfigTest) + }) +} diff --git a/cmd/neofs-node/main.go b/cmd/neofs-node/main.go index 807dce4c..67aca281 100644 --- a/cmd/neofs-node/main.go +++ b/cmd/neofs-node/main.go @@ -81,6 +81,7 @@ func initApp(c *cfg) { initAndLog(c, "pprof", initProfiler) initAndLog(c, "prometheus", initMetrics) initAndLog(c, "control", initControlService) + initAndLog(c, "tree", initTreeService) initAndLog(c, "storage engine", func(c *cfg) { fatalOnErr(c.cfgObject.cfgLocalStorage.localStorage.Open()) diff --git a/cmd/neofs-node/tree.go b/cmd/neofs-node/tree.go new file mode 100644 index 00000000..37dd331e --- /dev/null +++ b/cmd/neofs-node/tree.go @@ -0,0 +1,41 @@ +package main + +import ( + "context" + "net" + + treeconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/tree" + "github.com/nspcc-dev/neofs-node/pkg/services/tree" + "google.golang.org/grpc" +) + +func initTreeService(c *cfg) { + endpoint := treeconfig.GRPC(c.appCfg).Endpoint() + if endpoint == treeconfig.GRPCEndpointDefault { + return + } + + treeSvc := tree.New( + tree.WithContainerSource(c.cfgObject.cnrSource), + tree.WithNetmapSource(c.netMapSource), + tree.WithPrivateKey(&c.key.PrivateKey), + tree.WithLogger(c.log), + tree.WithStorage(c.cfgObject.cfgLocalStorage.localStorage)) + + treeServer := grpc.NewServer() + + c.onShutdown(func() { + stopGRPC("NeoFS Tree Service API", treeServer, c.log) + treeSvc.Shutdown() + }) + + lis, err := net.Listen("tcp", endpoint) + fatalOnErr(err) + + tree.RegisterTreeServiceServer(treeServer, treeSvc) + + c.workers = append(c.workers, newWorkerFromFunc(func(ctx context.Context) { + treeSvc.Start(ctx) + fatalOnErr(treeServer.Serve(lis)) + })) +} diff --git a/config/example/node.env b/config/example/node.env index 3c674ee7..1c31501f 100644 --- a/config/example/node.env +++ b/config/example/node.env @@ -46,6 +46,9 @@ NEOFS_GRPC_1_TLS_ENABLED=false NEOFS_CONTROL_AUTHORIZED_KEYS="035839e45d472a3b7769a2a1bd7d54c4ccd4943c3b40f547870e83a8fcbfb3ce11 028f42cfcb74499d7b15b35d9bff260a1c8d27de4f446a627406a382d8961486d6" NEOFS_CONTROL_GRPC_ENDPOINT=localhost:8090 +# Tree service section +NEOFS_TREE_GRPC_ENDPOINT=127.0.0.1:8091 + # Contracts section NEOFS_CONTRACTS_BALANCE=5263abba1abedbf79bb57f3e40b50b4425d2d6cd NEOFS_CONTRACTS_CONTAINER=5d084790d7aa36cea7b53fe897380dab11d2cd3c diff --git a/config/example/node.json b/config/example/node.json index 569aff46..b3ae7850 100644 --- a/config/example/node.json +++ b/config/example/node.json @@ -84,6 +84,11 @@ "endpoint": "localhost:8090" } }, + "tree": { + "grpc": { + "endpoint": "127.0.0.1:8091" + } + }, "contracts": { "balance": "5263abba1abedbf79bb57f3e40b50b4425d2d6cd", "container": "5d084790d7aa36cea7b53fe897380dab11d2cd3c", diff --git a/config/example/node.yaml b/config/example/node.yaml index b3eec638..3465eb07 100644 --- a/config/example/node.yaml +++ b/config/example/node.yaml @@ -66,6 +66,10 @@ control: grpc: endpoint: localhost:8090 # endpoint that is listened by the Control Service +tree: + grpc: + endpoint: 127.0.0.1:8091 # endpoint that is listened by the Tree Service + contracts: # side chain NEOFS contract script hashes; optional, override values retrieved from NNS contract balance: 5263abba1abedbf79bb57f3e40b50b4425d2d6cd container: 5d084790d7aa36cea7b53fe897380dab11d2cd3c diff --git a/go.mod b/go.mod index a6ccbecc..46a96c06 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,10 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) +require google.golang.org/api v0.44.0 + require ( + cloud.google.com/go v0.81.0 // indirect github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521073959-f0d4d129b7f1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect @@ -47,8 +50,10 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.3 // indirect + github.com/google/go-cmp v0.5.6 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -87,12 +92,15 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect github.com/twmb/murmur3 v1.1.5 // indirect github.com/urfave/cli v1.22.5 // indirect + go.opencensus.io v0.23.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect + golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/text v0.3.7 // indirect + google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 1c82bb69f13aec7693d7b5f0a71874b258a83896..c0f0a43ccf496d3ae2847fd60bf517cad6bd2667 100644 GIT binary patch delta 360 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 EpZIMXHvj+t literal 0 HcmV?d00001 diff --git a/pkg/services/tree/types.proto b/pkg/services/tree/types.proto new file mode 100644 index 00000000..420fa4df --- /dev/null +++ b/pkg/services/tree/types.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package tree; + +option go_package = "github.com/nspcc-dev/neofs-node/pkg/services/tree"; + +// KeyValue represents key-value pair attached to an object. +message KeyValue { + string key = 1 [json_name = "key"]; + bytes value = 2 [json_name = "value"]; +} + +// LogMove represents log-entry for a single move operation. +message LogMove { + // ID of the parent node. + uint64 parent_id = 2 [json_name = "parentID"]; + // Node meta information, including operation timestamp. + bytes meta = 3 [json_name = "meta"]; + // ID of the node to move. + uint64 child_id = 4 [json_name = "childID"]; +} + +// Signature of a message. +message Signature { + bytes key = 1 [json_name = "key"]; + bytes sign = 2 [json_name = "signature"]; +}