From f64ae55806a72c9eea01ae0c721755aebf43c525 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 19 Sep 2022 18:36:54 +0400 Subject: [PATCH] [#1681] ir/netmap: Require MAINTENANCE mode to be allowed by network There is a need to prevent limitless abuse of MAINTENANCE status of the storage nodes. To do this, configuration of the NeoFS network is going to be extended with the flag which allows the state. Until this is done, it makes sense to prepare a site for this in the code. Define `state.NetworkSettings` interface as an abstraction of global network configuration within the `state` package. Make `NetMapCandidateValidator` to depend on `NetworkSettings` and provide corresponding field setter. Change `VerifyAndUpdate` method's behavior to return an error for candidates with MAINTENANCE state if this state is disallowed by the network configuration. Provide `NetworkSettings` from the wrapper over Netmap contract's client on Inner Ring application side. The provider is implemented to statically disallow MAINTENANCE mode in order to save previous behavior. Signed-off-by: Leonard Lyubich Signed-off-by: Leonard Lyubich --- pkg/innerring/innerring.go | 1 + pkg/innerring/netmap.go | 20 +++++++++ .../netmap/nodevalidation/state/validator.go | 33 ++++++++++++-- .../nodevalidation/state/validator_test.go | 43 ++++++++++++++++++- 4 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 pkg/innerring/netmap.go diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go index d7b91ec58..51386c16e 100644 --- a/pkg/innerring/innerring.go +++ b/pkg/innerring/innerring.go @@ -691,6 +691,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper, errChan chan<- } var netMapCandidateStateValidator statevalidation.NetMapCandidateValidator + netMapCandidateStateValidator.SetNetworkSettings((*networkSettings)(server.netmapClient)) // create netmap processor server.netmapProcessor, err = netmap.New(&netmap.Params{ diff --git a/pkg/innerring/netmap.go b/pkg/innerring/netmap.go new file mode 100644 index 000000000..1df6848cc --- /dev/null +++ b/pkg/innerring/netmap.go @@ -0,0 +1,20 @@ +package innerring + +import ( + "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/nodevalidation/state" + netmapclient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap" +) + +/* +File contains dependencies for processor of the Netmap contract's notifications. +*/ + +// wraps Netmap contract's client and provides state.NetworkSettings. +type networkSettings netmapclient.Client + +// MaintenanceModeAllowed requests network configuration from the Sidechain +// and check allowance of storage node's maintenance mode according to it. +// Always returns state.ErrMaintenanceModeDisallowed. +func (s *networkSettings) MaintenanceModeAllowed() error { + return state.ErrMaintenanceModeDisallowed +} diff --git a/pkg/innerring/processors/netmap/nodevalidation/state/validator.go b/pkg/innerring/processors/netmap/nodevalidation/state/validator.go index 79093dde5..5638fc5c8 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/state/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/state/validator.go @@ -12,6 +12,20 @@ import ( "github.com/nspcc-dev/neofs-sdk-go/netmap" ) +// ErrMaintenanceModeDisallowed is returned when maintenance mode is disallowed. +var ErrMaintenanceModeDisallowed = errors.New("maintenance mode is disallowed") + +// NetworkSettings encapsulates current settings of the NeoFS network and +// provides interface used for processing the network map candidates. +type NetworkSettings interface { + // MaintenanceModeAllowed checks if maintenance state of the storage nodes + // is allowed to be set, and returns: + // no error if allowed; + // ErrMaintenanceModeDisallowed if disallowed; + // other error if there are any problems with the check. + MaintenanceModeAllowed() error +} + // NetMapCandidateValidator represents tool which checks state of nodes which // are going to register in the NeoFS network (enter the network map). // @@ -21,21 +35,34 @@ import ( // NetMapCandidateValidator implements // github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap.NodeValidator. type NetMapCandidateValidator struct { + netSettings NetworkSettings +} + +// SetNetworkSettings specifies provider of the NetworkSettings interface. +// MUST be called before any VerifyAndUpdate call. Parameter MUST NOT be nil. +func (x *NetMapCandidateValidator) SetNetworkSettings(netSettings NetworkSettings) { + x.netSettings = netSettings } // VerifyAndUpdate checks state of the network map candidate described by // netmap.NodeInfo parameter. Returns no error if status is correct, otherwise // returns an error describing a violation of the rules: // -// status MUST be ONLINE +// status MUST be either ONLINE or MAINTENANCE; +// if status is MAINTENANCE, then it SHOULD be allowed by the network. // // VerifyAndUpdate does not mutate the parameter in a binary format. +// MUST NOT be called before SetNetworkSettings. // -// See also netmap.NodeInfo.IsOnline/SetOnline. +// See also netmap.NodeInfo.IsOnline/SetOnline and other similar methods. func (x *NetMapCandidateValidator) VerifyAndUpdate(node *netmap.NodeInfo) error { if node.IsOnline() { return nil } - return errors.New("invalid status: MUST be ONLINE") + if node.IsMaintenance() { + return x.netSettings.MaintenanceModeAllowed() + } + + return errors.New("invalid status: MUST be either ONLINE or MAINTENANCE") } diff --git a/pkg/innerring/processors/netmap/nodevalidation/state/validator_test.go b/pkg/innerring/processors/netmap/nodevalidation/state/validator_test.go index 3d08a02d8..e1acf96a8 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/state/validator_test.go +++ b/pkg/innerring/processors/netmap/nodevalidation/state/validator_test.go @@ -8,13 +8,31 @@ import ( "github.com/stretchr/testify/require" ) +// implements state.NetworkSettings for testing. +type testNetworkSettings struct { + disallowed bool +} + +func (x testNetworkSettings) MaintenanceModeAllowed() error { + if x.disallowed { + return state.ErrMaintenanceModeDisallowed + } + + return nil +} + func TestValidator_VerifyAndUpdate(t *testing.T) { - var v state.NetMapCandidateValidator + var vDefault state.NetMapCandidateValidator + var s testNetworkSettings + + vDefault.SetNetworkSettings(s) for _, testCase := range []struct { name string preparer func(*netmap.NodeInfo) // modifies zero instance valid bool // is node valid after preparation + + validatorPreparer func(*state.NetMapCandidateValidator) // optionally modifies default validator }{ { name: "UNDEFINED", @@ -31,6 +49,22 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { preparer: (*netmap.NodeInfo).SetOffline, valid: false, }, + { + name: "MAINTENANCE/allowed", + preparer: (*netmap.NodeInfo).SetMaintenance, + valid: true, + }, + { + name: "MAINTENANCE/disallowed", + preparer: (*netmap.NodeInfo).SetMaintenance, + valid: false, + validatorPreparer: func(v *state.NetMapCandidateValidator) { + var s testNetworkSettings + s.disallowed = true + + v.SetNetworkSettings(s) + }, + }, } { var node netmap.NodeInfo @@ -40,6 +74,13 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { // save binary representation for mutation check binNode := node.Marshal() + var v state.NetMapCandidateValidator + if testCase.validatorPreparer == nil { + v = vDefault + } else { + testCase.validatorPreparer(&v) + } + err := v.VerifyAndUpdate(&node) if testCase.valid {