diff --git a/cmd/frostfs-ir/config.go b/cmd/frostfs-ir/config.go index be870052c..c73b68eb5 100644 --- a/cmd/frostfs-ir/config.go +++ b/cmd/frostfs-ir/config.go @@ -34,6 +34,7 @@ func reloadConfig() error { if err != nil { return err } + cmode.Store(cfg.GetBool("node.kludge_compatibility_mode")) err = logPrm.SetLevelString(cfg.GetString("logger.level")) if err != nil { return err diff --git a/cmd/frostfs-ir/defaults.go b/cmd/frostfs-ir/defaults.go index 127a68b29..23a475591 100644 --- a/cmd/frostfs-ir/defaults.go +++ b/cmd/frostfs-ir/defaults.go @@ -43,6 +43,8 @@ func defaultConfiguration(cfg *viper.Viper) { setControlDefaults(cfg) cfg.SetDefault("governance.disable", false) + + cfg.SetDefault("node.kludge_compatibility_mode", false) } func setControlDefaults(cfg *viper.Viper) { diff --git a/cmd/frostfs-ir/main.go b/cmd/frostfs-ir/main.go index 9879342b7..31390dd74 100644 --- a/cmd/frostfs-ir/main.go +++ b/cmd/frostfs-ir/main.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "sync" + "sync/atomic" "git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" "git.frostfs.info/TrueCloudLab/frostfs-node/misc" @@ -37,6 +38,7 @@ var ( cfg *viper.Viper configFile *string configDir *string + cmode = &atomic.Bool{} ) func exitErr(err error) { @@ -62,6 +64,8 @@ func main() { cfg, err = newConfig() exitErr(err) + cmode.Store(cfg.GetBool("node.kludge_compatibility_mode")) + metrics := irMetrics.NewInnerRingMetrics() err = logPrm.SetLevelString( @@ -84,7 +88,7 @@ func main() { metricsCmp = newMetricsComponent() metricsCmp.init() - innerRing, err = innerring.New(ctx, log, cfg, intErr, metrics) + innerRing, err = innerring.New(ctx, log, cfg, intErr, metrics, cmode) exitErr(err) pprofCmp.start() diff --git a/cmd/frostfs-node/config.go b/cmd/frostfs-node/config.go index 45ef771f3..d78a90cfc 100644 --- a/cmd/frostfs-node/config.go +++ b/cmd/frostfs-node/config.go @@ -109,6 +109,9 @@ type applicationConfiguration struct { lowMem bool rebuildWorkers uint32 } + + // if need to run node in compatibility with other versions mode + cmode *atomic.Bool } type shardCfg struct { @@ -204,10 +207,13 @@ func (a *applicationConfiguration) readConfig(c *config.Config) error { } // clear if it is rereading + cmode := a.cmode *a = applicationConfiguration{} + a.cmode = cmode } a._read = true + a.cmode.Store(nodeconfig.CompatibilityMode(c)) // Logger @@ -648,7 +654,11 @@ type cfgControlService struct { var persistateSideChainLastBlockKey = []byte("side_chain_last_processed_block") func initCfg(appCfg *config.Config) *cfg { - c := &cfg{} + c := &cfg{ + applicationConfiguration: applicationConfiguration{ + cmode: &atomic.Bool{}, + }, + } err := c.readConfig(appCfg) if err != nil { diff --git a/cmd/frostfs-node/config/node/config.go b/cmd/frostfs-node/config/node/config.go index ac76ad47e..90338556e 100644 --- a/cmd/frostfs-node/config/node/config.go +++ b/cmd/frostfs-node/config/node/config.go @@ -292,3 +292,8 @@ func (l PersistentPolicyRulesConfig) Perm() fs.FileMode { func (l PersistentPolicyRulesConfig) NoSync() bool { return config.BoolSafe((*config.Config)(l.cfg), "no_sync") } + +// CompatibilityMode returns true if need to run node in compatibility with previous versions mode. +func CompatibilityMode(c *config.Config) bool { + return config.BoolSafe(c.Sub(subsection), "kludge_compatibility_mode") +} diff --git a/cmd/frostfs-node/morph.go b/cmd/frostfs-node/morph.go index 1b148095b..b025f63ef 100644 --- a/cmd/frostfs-node/morph.go +++ b/cmd/frostfs-node/morph.go @@ -48,6 +48,7 @@ func initMorphComponents(ctx context.Context, c *cfg) { }), client.WithSwitchInterval(morphconfig.SwitchInterval(c.appCfg)), client.WithMorphCacheMetrics(c.metricsCollector.MorphCacheMetrics()), + client.WithCompatibilityMode(c.cmode), ) if err != nil { c.log.Info(logs.FrostFSNodeFailedToCreateNeoRPCClient, diff --git a/go.mod b/go.mod index 1d18bb9d3..ed1c03f06 100644 --- a/go.mod +++ b/go.mod @@ -40,8 +40,8 @@ require ( go.uber.org/zap v1.26.0 golang.org/x/exp v0.0.0-20240119083558-1b970713d09a golang.org/x/sync v0.6.0 - golang.org/x/sys v0.16.0 - golang.org/x/term v0.16.0 + golang.org/x/sys v0.18.0 + golang.org/x/term v0.18.0 google.golang.org/grpc v1.61.0 google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v3 v3.0.1 @@ -121,8 +121,8 @@ require ( go.opentelemetry.io/otel/sdk v1.22.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/net v0.20.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect diff --git a/go.sum b/go.sum index d90bf0f6a..a54f2f79a 100644 Binary files a/go.sum and b/go.sum differ diff --git a/pkg/innerring/initialization.go b/pkg/innerring/initialization.go index 1a4174289..783888b3d 100644 --- a/pkg/innerring/initialization.go +++ b/pkg/innerring/initialization.go @@ -462,6 +462,7 @@ func (s *Server) initMorph(ctx context.Context, cfg *viper.Viper, errChan chan<- name: morphPrefix, from: fromSideChainBlock, morphCacheMetric: s.irMetrics.MorphCacheMetrics(), + cmode: s.cmode, } // create morph client diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go index 5d7dc5a52..3cc203558 100644 --- a/pkg/innerring/innerring.go +++ b/pkg/innerring/innerring.go @@ -103,6 +103,8 @@ type ( // should report start errors // to the application. runners []func(chan<- error) error + + cmode *atomic.Bool } chainParams struct { @@ -113,6 +115,7 @@ type ( sgn *transaction.Signer from uint32 // block height morphCacheMetric metrics.MorphCacheMetrics + cmode *atomic.Bool } ) @@ -330,12 +333,13 @@ func (s *Server) registerStarter(f func() error) { // New creates instance of inner ring sever structure. func New(ctx context.Context, log *logger.Logger, cfg *viper.Viper, errChan chan<- error, - metrics *metrics.InnerRingServiceMetrics, + metrics *metrics.InnerRingServiceMetrics, cmode *atomic.Bool, ) (*Server, error) { var err error server := &Server{ log: log, irMetrics: metrics, + cmode: cmode, } server.sdNotify, err = server.initSdNotify(cfg) @@ -485,6 +489,7 @@ func createClient(ctx context.Context, p *chainParams, errChan chan<- error) (*c }), client.WithSwitchInterval(p.cfg.GetDuration(p.name+".switch_interval")), client.WithMorphCacheMetrics(p.morphCacheMetric), + client.WithCompatibilityMode(p.cmode), ) } diff --git a/pkg/local_object_storage/pilorama/heap.go b/pkg/local_object_storage/pilorama/heap.go index 667283c2a..50abb663c 100644 --- a/pkg/local_object_storage/pilorama/heap.go +++ b/pkg/local_object_storage/pilorama/heap.go @@ -17,6 +17,7 @@ func (h filenameHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *filenameHeap) Push(x any) { *h = append(*h, x.(heapInfo)) } + func (h *filenameHeap) Pop() any { old := *h n := len(old) diff --git a/pkg/morph/client/constructor.go b/pkg/morph/client/constructor.go index 50a9572d4..956ebfb31 100644 --- a/pkg/morph/client/constructor.go +++ b/pkg/morph/client/constructor.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "sync/atomic" "time" "git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" @@ -48,6 +49,8 @@ type cfg struct { switchInterval time.Duration morphCacheMetrics metrics.MorphCacheMetrics + + cmode *atomic.Bool } const ( @@ -311,3 +314,11 @@ func WithMorphCacheMetrics(morphCacheMetrics metrics.MorphCacheMetrics) Option { c.morphCacheMetrics = morphCacheMetrics } } + +// WithCompatibilityMode indicates that Client is working in compatibility mode +// in this mode we need to keep backward compatibility with services with previous version. +func WithCompatibilityMode(cmode *atomic.Bool) Option { + return func(c *cfg) { + c.cmode = cmode + } +} diff --git a/pkg/morph/client/notary.go b/pkg/morph/client/notary.go index 1665fec1d..564384a3d 100644 --- a/pkg/morph/client/notary.go +++ b/pkg/morph/client/notary.go @@ -566,14 +566,19 @@ func (c *Client) notaryCosigners(invokedByAlpha bool, ir []*keys.PublicKey, comm } s := make([]actor.SignerAccount, 2, 3) // Proxy contract that will pay for the execution. + // Do not change this: + // We must be able to call NNS contract indirectly from the Container contract. + // Thus, CalledByEntry is not sufficient. + // In future we may restrict this to all the usecases we have. + scopes := transaction.Global + if c.cfg.cmode != nil && c.cfg.cmode.Load() { + // Set it to None to keep ability to send notary requests during upgrade + scopes = transaction.None + } s[0] = actor.SignerAccount{ Signer: transaction.Signer{ Account: c.notary.proxy, - // Do not change this: - // We must be able to call NNS contract indirectly from the Container contract. - // Thus, CalledByEntry is not sufficient. - // In future we may restrict this to all the usecases we have. - Scopes: transaction.Global, + Scopes: scopes, }, Account: notary.FakeContractAccount(c.notary.proxy), } diff --git a/pkg/services/tree/getsubtree_test.go b/pkg/services/tree/getsubtree_test.go index 4bf679984..9a4223e30 100644 --- a/pkg/services/tree/getsubtree_test.go +++ b/pkg/services/tree/getsubtree_test.go @@ -130,7 +130,7 @@ func TestGetSubTreeOrderAsc(t *testing.T) { t.Run("boltdb forest", func(t *testing.T) { p := pilorama.NewBoltForest(pilorama.WithPath(filepath.Join(t.TempDir(), "pilorama"))) - require.NoError(t, p.Open(context.Background(), 0644)) + require.NoError(t, p.Open(context.Background(), 0o644)) require.NoError(t, p.Init()) testGetSubTreeOrderAsc(t, p) })