From 1406d096a21309fb8beeeb7a4a31f51b2ce5610a Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Fri, 14 Oct 2022 13:35:19 +0400 Subject: [PATCH] [#1680] service/object: Fail all operations in maintenance mode Storage node should not provide NeoFS Object API service when it is under maintenance. Declare `Common` service that unifies behavior of all object operations. The implementation pre-checks if node is under maintenance and returns `apistatus.NodeUnderMaintenance` if so. Use `Common` service as a first logical processor in object service pipeline. Signed-off-by: Leonard Lyubich --- cmd/neofs-node/object.go | 19 ++---- pkg/services/object/common.go | 91 ++++++++++++++++++++++++++ pkg/services/object/get/service.go | 7 -- pkg/services/object/get/util.go | 8 --- pkg/services/object/search/service.go | 3 +- pkg/services/object/search/util.go | 8 --- pkg/services/object/util/node_state.go | 9 --- 7 files changed, 98 insertions(+), 47 deletions(-) create mode 100644 pkg/services/object/common.go delete mode 100644 pkg/services/object/util/node_state.go diff --git a/cmd/neofs-node/object.go b/cmd/neofs-node/object.go index d9815ae0..b20d4490 100644 --- a/cmd/neofs-node/object.go +++ b/cmd/neofs-node/object.go @@ -254,8 +254,7 @@ func initObjectService(c *cfg) { c.workers = append(c.workers, pol) var os putsvc.ObjectStorage = engineWithoutNotifications{ - e: ls, - state: &c.internals, + e: ls, } if c.cfgNotifications.enabled { @@ -291,7 +290,7 @@ func initObjectService(c *cfg) { sSearch := searchsvc.New( searchsvc.WithLogger(c.log), - searchsvc.WithLocalStorageEngine(ls, &c.internals), + searchsvc.WithLocalStorageEngine(ls), searchsvc.WithClientConstructor(coreConstructor), searchsvc.WithTraverserGenerator( traverseGen.WithTraverseOptions( @@ -318,7 +317,6 @@ func initObjectService(c *cfg) { ), getsvc.WithNetMapSource(c.netMapSource), getsvc.WithKeyStorage(keyStorage), - getsvc.WithNodeState(&c.internals), ) *c.cfgObject.getSvc = *sGet // need smth better @@ -378,8 +376,11 @@ func initObjectService(c *cfg) { ), ) + var commonSvc objectService.Common + commonSvc.Init(&c.internals, aclSvc) + respSvc := objectService.NewResponseService( - aclSvc, + &commonSvc, c.respSvc, ) @@ -583,16 +584,8 @@ func (e engineWithNotifications) Put(o *objectSDK.Object) error { type engineWithoutNotifications struct { e *engine.StorageEngine - - state util.NodeState } func (e engineWithoutNotifications) Put(o *objectSDK.Object) error { - if e.state.IsMaintenance() { - var st apistatus.NodeUnderMaintenance - - return st - } - return engine.Put(e.e, o) } diff --git a/pkg/services/object/common.go b/pkg/services/object/common.go new file mode 100644 index 00000000..babce3c4 --- /dev/null +++ b/pkg/services/object/common.go @@ -0,0 +1,91 @@ +package object + +import ( + "context" + + objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object" + apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" +) + +// NodeState is storage node state processed by Object service. +type NodeState interface { + // IsMaintenance checks if node is under maintenance. Node MUST NOT serve + // local object operations. Node MUST respond with apistatus.NodeUnderMaintenance + // error if IsMaintenance returns true. + IsMaintenance() bool +} + +// Common is an Object API ServiceServer which encapsulates logic spread to all +// object operations. +// +// If underlying NodeState.IsMaintenance returns true, all operations are +// immediately failed with apistatus.NodeUnderMaintenance. +type Common struct { + state NodeState + + nextHandler ServiceServer +} + +// Init initializes the Common instance. +func (x *Common) Init(state NodeState, nextHandler ServiceServer) { + x.state = state + x.nextHandler = nextHandler +} + +var errMaintenance apistatus.NodeUnderMaintenance + +func (x *Common) Get(req *objectV2.GetRequest, stream GetObjectStream) error { + if x.state.IsMaintenance() { + return errMaintenance + } + + return x.nextHandler.Get(req, stream) +} + +func (x *Common) Put(ctx context.Context) (PutObjectStream, error) { + if x.state.IsMaintenance() { + return nil, errMaintenance + } + + return x.nextHandler.Put(ctx) +} + +func (x *Common) Head(ctx context.Context, req *objectV2.HeadRequest) (*objectV2.HeadResponse, error) { + if x.state.IsMaintenance() { + return nil, errMaintenance + } + + return x.nextHandler.Head(ctx, req) +} + +func (x *Common) Search(req *objectV2.SearchRequest, stream SearchStream) error { + if x.state.IsMaintenance() { + return errMaintenance + } + + return x.nextHandler.Search(req, stream) +} + +func (x *Common) Delete(ctx context.Context, req *objectV2.DeleteRequest) (*objectV2.DeleteResponse, error) { + if x.state.IsMaintenance() { + return nil, errMaintenance + } + + return x.nextHandler.Delete(ctx, req) +} + +func (x *Common) GetRange(req *objectV2.GetRangeRequest, stream GetObjectRangeStream) error { + if x.state.IsMaintenance() { + return errMaintenance + } + + return x.nextHandler.GetRange(req, stream) +} + +func (x *Common) GetRangeHash(ctx context.Context, req *objectV2.GetRangeHashRequest) (*objectV2.GetRangeHashResponse, error) { + if x.state.IsMaintenance() { + return nil, errMaintenance + } + + return x.nextHandler.GetRangeHash(ctx, req) +} diff --git a/pkg/services/object/get/service.go b/pkg/services/object/get/service.go index c4d32865..1e105eb4 100644 --- a/pkg/services/object/get/service.go +++ b/pkg/services/object/get/service.go @@ -130,10 +130,3 @@ func WithKeyStorage(store *util.KeyStorage) Option { c.keyStore = store } } - -// WithNodeState provides util.NodeState to Service. -func WithNodeState(v util.NodeState) Option { - return func(c *cfg) { - c.localStorage.(*storageEngineWrapper).state = v - } -} diff --git a/pkg/services/object/get/util.go b/pkg/services/object/get/util.go index 5fa364ab..e77940bf 100644 --- a/pkg/services/object/get/util.go +++ b/pkg/services/object/get/util.go @@ -10,7 +10,6 @@ import ( "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine" internal "github.com/nspcc-dev/neofs-node/pkg/services/object/internal/client" internalclient "github.com/nspcc-dev/neofs-node/pkg/services/object/internal/client" - "github.com/nspcc-dev/neofs-node/pkg/services/object/util" apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" "github.com/nspcc-dev/neofs-sdk-go/object" ) @@ -30,8 +29,6 @@ type clientWrapper struct { } type storageEngineWrapper struct { - state util.NodeState - engine *engine.StorageEngine } @@ -199,11 +196,6 @@ func (c *clientWrapper) get(exec *execCtx, key *ecdsa.PrivateKey) (*object.Objec } func (e *storageEngineWrapper) get(exec *execCtx) (*object.Object, error) { - if e.state != nil && e.state.IsMaintenance() { - var st apistatus.NodeUnderMaintenance - return nil, st - } - if exec.headOnly() { var headPrm engine.HeadPrm headPrm.WithAddress(exec.address()) diff --git a/pkg/services/object/search/service.go b/pkg/services/object/search/service.go index 76d0a3bf..4a655aa7 100644 --- a/pkg/services/object/search/service.go +++ b/pkg/services/object/search/service.go @@ -83,10 +83,9 @@ func WithLogger(l *logger.Logger) Option { // WithLocalStorageEngine returns option to set local storage // instance. -func WithLocalStorageEngine(e *engine.StorageEngine, state util.NodeState) Option { +func WithLocalStorageEngine(e *engine.StorageEngine) Option { return func(c *cfg) { c.localStorage = &storageEngineWrapper{ - state: state, storage: e, } } diff --git a/pkg/services/object/search/util.go b/pkg/services/object/search/util.go index e32dcb2f..fd73cef9 100644 --- a/pkg/services/object/search/util.go +++ b/pkg/services/object/search/util.go @@ -9,7 +9,6 @@ import ( internalclient "github.com/nspcc-dev/neofs-node/pkg/services/object/internal/client" "github.com/nspcc-dev/neofs-node/pkg/services/object/util" "github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement" - apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" ) @@ -31,8 +30,6 @@ type clientWrapper struct { } type storageEngineWrapper struct { - state util.NodeState - storage *engine.StorageEngine } @@ -121,11 +118,6 @@ func (c *clientWrapper) searchObjects(exec *execCtx, info client.NodeInfo) ([]oi } func (e *storageEngineWrapper) search(exec *execCtx) ([]oid.ID, error) { - if e.state != nil && e.state.IsMaintenance() { - var st apistatus.NodeUnderMaintenance - return nil, st - } - var selectPrm engine.SelectPrm selectPrm.WithFilters(exec.searchFilters()) selectPrm.WithContainerID(exec.containerID()) diff --git a/pkg/services/object/util/node_state.go b/pkg/services/object/util/node_state.go deleted file mode 100644 index 7ef31e3c..00000000 --- a/pkg/services/object/util/node_state.go +++ /dev/null @@ -1,9 +0,0 @@ -package util - -// NodeState is storage node state processed by Object service. -type NodeState interface { - // IsMaintenance checks if node is under maintenance. Node MUST NOT serve - // local object operations. Node MUST respond with apistatus.NodeUnderMaintenance - // error if IsMaintenance returns true. - IsMaintenance() bool -}