diff --git a/client/client.go b/client/client.go index dea80c1..98fad3d 100644 --- a/client/client.go +++ b/client/client.go @@ -35,6 +35,7 @@ import ( // All possible responses are documented in methods, however, some may be // returned from all of them (pay attention to the presence of the pointer sign): // - *apistatus.ServerInternal on internal server error; +// - *apistatus.NodeUnderMaintenance if a server is under maintenance; // - *apistatus.SuccessDefaultV2 on default success. // // Client MUST NOT be copied by value: use pointer to Client instead. diff --git a/client/status/common.go b/client/status/common.go index 58c2540..7c86f3c 100644 --- a/client/status/common.go +++ b/client/status/common.go @@ -174,3 +174,48 @@ func (x *SignatureVerification) SetMessage(v string) { func (x SignatureVerification) Message() string { return x.v2.Message() } + +// NodeUnderMaintenance describes failure status for nodes being under maintenance. +// Instances provide Status and StatusV2 interfaces. +type NodeUnderMaintenance struct { + v2 status.Status +} + +// Error implements the error interface. +func (x NodeUnderMaintenance) Error() string { + return errMessageStatusV2( + globalizeCodeV2(status.NodeUnderMaintenance, status.GlobalizeCommonFail), + x.v2.Message(), + ) +} + +func (x *NodeUnderMaintenance) fromStatusV2(st *status.Status) { + x.v2 = *st +} + +// ToStatusV2 implements StatusV2 interface method. +// If the value was returned by FromStatusV2, returns the source message. +// Otherwise, returns message with +// - code: NODE_UNDER_MAINTENANCE; +// - string message: written message via SetMessage; +// - details: empty. +func (x NodeUnderMaintenance) ToStatusV2() *status.Status { + x.v2.SetCode(globalizeCodeV2(status.NodeUnderMaintenance, status.GlobalizeCommonFail)) + return &x.v2 +} + +// SetMessage writes signature verification failure message. +// Message should be used for debug purposes only. +// +// See also Message. +func (x *NodeUnderMaintenance) SetMessage(v string) { + x.v2.SetMessage(v) +} + +// Message returns status message. Zero status returns empty message. +// Message should be used for debug purposes only. +// +// See also SetMessage. +func (x NodeUnderMaintenance) Message() string { + return x.v2.Message() +} diff --git a/client/status/common_test.go b/client/status/common_test.go index 204bd1a..032263a 100644 --- a/client/status/common_test.go +++ b/client/status/common_test.go @@ -89,3 +89,42 @@ func TestSignatureVerification(t *testing.T) { require.Equal(t, msg, stV2.Message()) }) } + +func TestNodeUnderMaintenance(t *testing.T) { + t.Run("default", func(t *testing.T) { + var st apistatus.NodeUnderMaintenance + + require.Empty(t, st.Message()) + }) + + t.Run("custom message", func(t *testing.T) { + var st apistatus.NodeUnderMaintenance + msg := "some message" + + st.SetMessage(msg) + + stV2 := st.ToStatusV2() + + require.Equal(t, msg, st.Message()) + require.Equal(t, msg, stV2.Message()) + }) + + t.Run("empty to V2", func(t *testing.T) { + var st apistatus.NodeUnderMaintenance + + stV2 := st.ToStatusV2() + + require.Empty(t, "", stV2.Message()) + }) + + t.Run("non-empty to V2", func(t *testing.T) { + var st apistatus.NodeUnderMaintenance + msg := "some other msg" + + st.SetMessage(msg) + + stV2 := st.ToStatusV2() + + require.Equal(t, msg, stV2.Message()) + }) +} diff --git a/go.mod b/go.mod index 25e512d..d4cf8b8 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/nspcc-dev/hrw v1.0.9 github.com/nspcc-dev/neo-go v0.99.2 - github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220827080658-9e17cdfc7647 + github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220916145053-f3e1f8ae7ae3 github.com/nspcc-dev/neofs-contract v0.15.3 github.com/nspcc-dev/tzhash v1.6.1 github.com/stretchr/testify v1.7.0 @@ -38,7 +38,7 @@ require ( golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 // indirect - google.golang.org/grpc v1.41.0 // indirect + google.golang.org/grpc v1.48.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index f214d09..e601ef1 100644 --- a/go.sum +++ b/go.sum @@ -81,7 +81,11 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -96,6 +100,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -258,8 +263,8 @@ github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220809123759-3094d3e0c14b h1:J7 github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220809123759-3094d3e0c14b/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s= github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs= -github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220827080658-9e17cdfc7647 h1:00JDCprdZG15n8z58EaFvJlmvZ4uESUii8MSzk869JM= -github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220827080658-9e17cdfc7647/go.mod h1:NAaDfOnFWIbAFkTj7pNQ+cknVue0JbdeRT9QQaeBCEY= +github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220916145053-f3e1f8ae7ae3 h1:ZPulLHstChUJBKzRcfRSAwZWAZ+jMpPRtSE4Q4EERqM= +github.com/nspcc-dev/neofs-api-go/v2 v2.13.2-0.20220916145053-f3e1f8ae7ae3/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-contract v0.15.3 h1:7+NwyTtxFAnIevz0hR/XxQf6R2Ej2scjVR2bnnJnhBM= github.com/nspcc-dev/neofs-contract v0.15.3/go.mod h1:BXVZUZUJxrmmDETglXHI8+5DSgn84B9y5DoSWqEjYCs= github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA= @@ -520,6 +525,7 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -659,8 +665,9 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -674,6 +681,7 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/abiosoft/ishell.v2 v2.0.0/go.mod h1:sFp+cGtH6o4s1FtpVPTMcHq2yue+c4DGOVohJCPUzwY= diff --git a/pool/pool.go b/pool/pool.go index ee716ef..c28deb4 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -810,7 +810,8 @@ func (c *clientStatusMonitor) handleError(st apistatus.Status, err error) error switch err.(type) { case apistatus.ServerInternal, *apistatus.ServerInternal, apistatus.WrongMagicNumber, *apistatus.WrongMagicNumber, - apistatus.SignatureVerification, *apistatus.SignatureVerification: + apistatus.SignatureVerification, *apistatus.SignatureVerification, + apistatus.NodeUnderMaintenance, *apistatus.NodeUnderMaintenance: c.incErrorRate() } diff --git a/pool/pool_test.go b/pool/pool_test.go index 245724c..7275835 100644 --- a/pool/pool_test.go +++ b/pool/pool_test.go @@ -588,6 +588,12 @@ func TestHandleError(t *testing.T) { expectedError: true, countError: true, }, + { + status: apistatus.NodeUnderMaintenance{}, + err: nil, + expectedError: true, + countError: true, + }, } { t.Run(strconv.Itoa(i), func(t *testing.T) { errCount := monitor.currentErrorRate()