diff --git a/CHANGELOG.md b/CHANGELOG.md index 647799ef2c1..dac55cba492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Changelog for NeoFS Node - Stored payload metric per shard (#2023) - Histogram metrics for RPC and engine operations (#2351) - SN's version is announced via the attributes automatically but can be overwritten explicitly (#2455) +- SN's capacity is announced via the attributes automatically but can be overwritten explicitly (#602) ### Fixed - `neo-go` RPC connection loss handling (#1337) diff --git a/cmd/neofs-node/config.go b/cmd/neofs-node/config.go index 5644ef7b205..9554b5187e7 100644 --- a/cmd/neofs-node/config.go +++ b/cmd/neofs-node/config.go @@ -9,6 +9,7 @@ import ( "os" "os/signal" "path/filepath" + "strconv" "strings" "sync" atomicstd "sync/atomic" @@ -532,16 +533,17 @@ var persistateSideChainLastBlockKey = []byte("side_chain_last_processed_block") func initCfg(appCfg *config.Config) *cfg { c := &cfg{} - // attaching version to the node's attributes; do not - // move it anywhere below reading the other attributes - // since a user should be able to overwrite it. - writeAppVersion(c) - err := c.readConfig(appCfg) if err != nil { panic(fmt.Errorf("config reading: %w", err)) } + // filling system attributes; do not move it anywhere + // below applying the other attributes since a user + // should be able to overwrite it. + err = writeSystemAttributes(c) + fatalOnErr(err) + key := nodeconfig.Key(appCfg) var netAddr network.AddressGroup @@ -969,8 +971,45 @@ func (c *cfg) configWatcher(ctx context.Context) { } } -// writeAppVersion writes app version as defined at compilation -// step to the node's attributes. -func writeAppVersion(c *cfg) { +// writeSystemAttributes writes app version as defined at compilation +// step to the node's attributes and an aggregated disk capacity +// according to the all space on the all configured disks. +func writeSystemAttributes(c *cfg) error { + // `Version` attribute + c.cfgNodeInfo.localInfo.SetAttribute("Version", misc.Version) + + // `Capacity` attribute + + var stat syscall.Statfs_t + var total uint64 // bytes + fsIDMap := make(map[syscall.Fsid]struct{}) + + for _, sh := range c.applicationConfiguration.EngineCfg.shards { + for _, storage := range sh.subStorages { + path := storage.path + + err := util.MkdirAllX(path, storage.perm) + if err != nil { + return fmt.Errorf("can not create (ensure it exists) dir by '%s' path: %w", path, err) + } + + err = syscall.Statfs(path, &stat) + if err != nil { + return fmt.Errorf("get FS stat by '%s' path: %w", path, err) + } + + if _, handled := fsIDMap[stat.Fsid]; handled { + continue + } + + total += stat.Blocks * uint64(stat.Bsize) + fsIDMap[stat.Fsid] = struct{}{} + } + } + + // according to API description, in GB, not GiB + c.cfgNodeInfo.localInfo.SetAttribute("Capacity", strconv.FormatUint(total/(1000*1000*1000), 10)) + + return nil }