diff --git a/CHANGELOG.md b/CHANGELOG.md index 858b6c242f..e704343d5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ attribute, which is used for container domain name in NNS contracts (#2954) - New `peapod-to-fstree` tool providing peapod-to-fstree data migration (#3013) - Reloading node attributes with SIGHUP (#3005) - Reloading pool sizes (#3018) +- Add metrics for shard's capacity (#3021) ### Fixed - Do not search for tombstones when handling their expiration, use local indexes instead (#2929) diff --git a/cmd/neofs-node/main.go b/cmd/neofs-node/main.go index 86e362e516..428ae172bf 100644 --- a/cmd/neofs-node/main.go +++ b/cmd/neofs-node/main.go @@ -61,6 +61,9 @@ func main() { initApp(c) + err = c.setShardsCapacity() + fatalOnErr(err) + c.setHealthStatus(control.HealthStatus_STARTING) bootUp(c) diff --git a/cmd/neofs-node/metrics.go b/cmd/neofs-node/metrics.go index a3899a92e5..f95a9aaa97 100644 --- a/cmd/neofs-node/metrics.go +++ b/cmd/neofs-node/metrics.go @@ -1,6 +1,12 @@ package main import ( + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" + metricsconfig "github.com/nspcc-dev/neofs-node/cmd/neofs-node/config/metrics" httputil "github.com/nspcc-dev/neofs-node/pkg/util/http" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -25,3 +31,34 @@ func initMetrics(c *cfg) *httputil.Server { return srv } + +func (c *cfg) setShardsCapacity() error { + for _, sh := range c.cfgObject.cfgLocalStorage.localStorage.DumpInfo().Shards { + paths := make([]string, 0, len(sh.BlobStorInfo.SubStorages)) + for _, subStorage := range sh.BlobStorInfo.SubStorages { + path := subStorage.Path + + for len(path) > 1 { // Dir returns / or . if nothing else left. + fi, err := os.Stat(path) + if err == nil && fi.IsDir() { + break + } + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("accessing %q: %w", path, err) + } + path = filepath.Dir(path) + } + + paths = append(paths, path) + } + + capacity, err := totalBytes(paths) + if err != nil { + return fmt.Errorf("calculating capacity on shard %s: %w", sh.ID.String(), err) + } + + c.metricsCollector.SetCapacitySize(sh.ID.String(), capacity/(1<<30)) + } + + return nil +} diff --git a/pkg/metrics/engine.go b/pkg/metrics/engine.go index 71a4d3cf2e..01b130b860 100644 --- a/pkg/metrics/engine.go +++ b/pkg/metrics/engine.go @@ -22,6 +22,7 @@ type ( containerSize prometheus.GaugeVec payloadSize prometheus.GaugeVec + capacitySize prometheus.GaugeVec } ) @@ -121,6 +122,13 @@ func newEngineMetrics() engineMetrics { Name: "payload_size", Help: "Accumulated size of all objects in a shard", }, []string{shardIDLabelKey}) + + capacitySize = prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Namespace: storageNodeNameSpace, + Subsystem: engineSubsystem, + Name: "capacity", + Help: "Contains the shard's capacity, GB", + }, []string{shardIDLabelKey}) ) return engineMetrics{ @@ -137,6 +145,7 @@ func newEngineMetrics() engineMetrics { listObjectsDuration: listObjectsDuration, containerSize: *containerSize, payloadSize: *payloadSize, + capacitySize: *capacitySize, } } @@ -154,6 +163,7 @@ func (m engineMetrics) register() { prometheus.MustRegister(m.listObjectsDuration) prometheus.MustRegister(m.containerSize) prometheus.MustRegister(m.payloadSize) + prometheus.MustRegister(m.capacitySize) } func (m engineMetrics) AddListContainersDuration(d time.Duration) { @@ -211,3 +221,7 @@ func (m engineMetrics) AddToContainerSize(cnrID string, size int64) { func (m engineMetrics) AddToPayloadCounter(shardID string, size int64) { m.payloadSize.With(prometheus.Labels{shardIDLabelKey: shardID}).Add(float64(size)) } + +func (m engineMetrics) SetCapacitySize(shardID string, capacity uint64) { + m.capacitySize.With(prometheus.Labels{shardIDLabelKey: shardID}).Set(float64(capacity)) +}