Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Changelog for NeoFS Node
### Added

### Fixed
- gRPC SIGHUP reload no longer stops a running public API before replacement configuration is verified (#4113)
- Storage node validates configuration and completes systemd reload notification on SIGHUP (#4113)
- Invalid node attributes on SIGHUP no longer terminate a storage node (#4113)

### Changed

Expand Down
14 changes: 9 additions & 5 deletions cmd/neofs-node/attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,26 @@ import (
"go.uber.org/zap"
)

func parseAttributes(c *cfg) {
func parseAttributes(c *cfg) error {
if c.appCfg.Node.Relay {
return
return nil
}

fatalOnErr(attributes.ReadNodeAttributes(&c.cfgNodeInfo.localInfo, c.appCfg.Node.Attributes))
if err := attributes.ReadNodeAttributes(&c.cfgNodeInfo.localInfo, c.appCfg.Node.Attributes); err != nil {
return err
}

// expand UN/LOCODE attribute if any found; keep user's attributes
// if any conflicts appear

locAttr := c.cfgNodeInfo.localInfo.LOCODE()
if locAttr == "" {
return
return nil
}

record, err := getRecord(locAttr)
if err != nil {
fatalOnErr(fmt.Errorf("could not get locode record from DB: %w", err))
return fmt.Errorf("could not get locode record from DB: %w", err)
}

countryCode := locAttr[:locodedb.CountryCodeLen]
Expand Down Expand Up @@ -84,6 +86,8 @@ func parseAttributes(c *cfg) {
} else {
setIfNotEmpty(n.SetSubdivisionName, record.SubDivName)
}

return nil
}

func getRecord(lc string) (locodedb.Record, error) {
Expand Down
106 changes: 56 additions & 50 deletions cmd/neofs-node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ type cfgGRPC struct {

listeners []net.Listener
servers []*grpc.Server
config grpcConfigSnapshot

// serviceRegistrators stores functions that register gRPC service
// implementations into a gRPC server.
Expand All @@ -251,7 +252,9 @@ func (g *cfgGRPC) registerService(f func(*grpc.Server)) {

g.serviceRegistrators = append(g.serviceRegistrators, f)
for _, srv := range g.servers {
f(srv)
if srv != nil {
f(srv)
}
}
}

Expand Down Expand Up @@ -626,7 +629,6 @@ func (c *cfg) needBootstrap() bool {
}

func (c *cfg) configWatcher(ctx context.Context) {
var err error
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGHUP)

Expand All @@ -639,74 +641,78 @@ func (c *cfg) configWatcher(ctx context.Context) {
c.log.Warn("failed to notify systemd about reloading", zap.Error(err))
}

oldMetrics := writeMetricConfig(c.appCfg)
oldProfiler := writeProfilerConfig(c.appCfg)
oldGRPC := writeGRPCConfig(c.appCfg)
if err := c.reloadConfig(); err != nil {
c.log.Error("configuration reload", zap.Error(err))
} else {
c.log.Info("configuration has been reloaded successfully")
}

c.appCfg, err = config.New(config.WithConfigFile(c.appCfg.Path()))
if err != nil {
c.log.Error("configuration reading", zap.Error(err))
continue
if err := sdnotify.Send(sdnotify.Ready); err != nil {
c.log.Warn("failed to notify systemd about readiness after reload", zap.Error(err))
}
case <-ctx.Done():
return
}
}
}

// Prometheus and pprof
//nolint:contextcheck // Reloading HTTP services does not receive a request context.
func (c *cfg) reloadConfig() error {
oldCfg := c.appCfg
oldMetrics := writeMetricConfig(oldCfg)
oldProfiler := writeProfilerConfig(oldCfg)

// nolint:contextcheck
c.reloadMetricsAndPprof(oldMetrics, oldProfiler)
newCfg, err := config.New(config.WithConfigFile(oldCfg.Path()))
if err != nil {
return fmt.Errorf("read configuration: %w", err)
}
if err := validateConfig(newCfg); err != nil {
return fmt.Errorf("validate configuration: %w", err)
}
c.appCfg = newCfg

// Logger
// Prometheus and pprof

err = c.logLevel.UnmarshalText([]byte(c.appCfg.Logger.Level))
if err != nil {
c.log.Error("invalid logger level configuration", zap.Error(err))
continue
}
c.reloadMetricsAndPprof(oldMetrics, oldProfiler)

// Policer
// Logger

c.policer.Reload(c.policerOpts()...)
if err := c.logLevel.UnmarshalText([]byte(c.appCfg.Logger.Level)); err != nil {
return fmt.Errorf("set logger level: %w", err)
}

// Storage Engine
// Policer

var rcfg engine.ReConfiguration
for _, optsWithID := range c.shardOpts() {
rcfg.AddShard(optsWithID.configID, optsWithID.shOpts)
}
c.policer.Reload(c.policerOpts()...)

err = c.cfgObject.cfgLocalStorage.localStorage.Reload(rcfg)
if err != nil {
c.log.Error("storage engine configuration update", zap.Error(err))
continue
}
// Storage Engine

// Morph
var rcfg engine.ReConfiguration
for _, optsWithID := range c.shardOpts() {
rcfg.AddShard(optsWithID.configID, optsWithID.shOpts)
}

c.cli.Reload(client.WithEndpoints(c.appCfg.FSChain.Endpoints))
if err := c.cfgObject.cfgLocalStorage.localStorage.Reload(rcfg); err != nil {
return fmt.Errorf("update storage engine configuration: %w", err)
}

// Node
// Morph

err = c.reloadNodeAttributes()
if err != nil {
c.log.Error("invalid node attributes configuration", zap.Error(err))
continue
}
c.cli.Reload(client.WithEndpoints(c.appCfg.FSChain.Endpoints))

// gRPC
// Node

if err = reloadGRPC(c, oldGRPC); err != nil {
c.log.Error("gRPC configuration reload", zap.Error(err))
continue
}
if err := c.reloadNodeAttributes(); err != nil {
return fmt.Errorf("update node attributes: %w", err)
}

c.log.Info("configuration has been reloaded successfully")
// gRPC

if err := sdnotify.Send(sdnotify.Ready); err != nil {
c.log.Warn("failed to notify systemd about readiness after reload", zap.Error(err))
}
case <-ctx.Done():
return
}
if err := reloadGRPC(c); err != nil {
return fmt.Errorf("reload gRPC configuration: %w", err)
}

return nil
}

// writeSystemAttributes writes app version as defined at compilation
Expand Down
Loading
Loading