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 {