Skip to content

Commit

Permalink
neofs-lens: storage status new command
Browse files Browse the repository at this point in the history
This command prints out information about storage and its components,
where object is located. It can be useful for object inspection and
storage health check.

Refs: #2550.

Signed-off-by: Ekaterina Pavlova <[email protected]>
  • Loading branch information
AliceInHunterland committed Sep 25, 2023
1 parent 9207437 commit 6163fa2
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Changelog for NeoFS Node

## [Unreleased]

## Added
- `neofs-lens storage status` CLI command (#2550)

### Fixed
- `neofs-cli netmap netinfo` documentation (#2555)
- `GETRANGEHASH` to a node without an object produced `GETRANGE` or `GET` requests (#2541)
Expand Down
28 changes: 28 additions & 0 deletions cmd/neofs-lens/internal/printers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package common

import (
"os"
"strings"

"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/engine"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
Expand Down Expand Up @@ -67,3 +69,29 @@ func WriteObjectToFile(cmd *cobra.Command, path string, data []byte, payloadOnly
}
cmd.Printf("\nSaved object to '%s' file\n", path)
}

// PrintStorageObjectStatus prints object status .
func PrintStorageObjectStatus(cmd *cobra.Command, status engine.ObjectStatus) {
//cmd.Println("Object status: ", status)
for _, shard := range status.Shards {
cmd.Println("Shard ID: ", shard.ID)
for i, subblobs := range shard.Shard.Blob.Substorages {
cmd.Println(" Substorage ", i)
cmd.Println(" Blob Type: ", subblobs.Type)
cmd.Println(" Blob Path: ", subblobs.Path)
cmd.Println(" Blob Error: ", subblobs.Error)
}
cmd.Println(" Metabase")
cmd.Println(" Metabase storage ID: ", shard.Shard.Metabase.StorageID)
cmd.Println(" Metabase path: ", shard.Shard.Metabase.Path)
cmd.Println(" Metabase object status: ", strings.Join(shard.Shard.Metabase.State, " "))
cmd.Println(" Metabase object error: ", shard.Shard.Metabase.Error)

cmd.Println(" Writecache")
cmd.Println(" Writecache DB path: ", shard.Shard.Writecache.PathDB)
cmd.Println(" Writecache DB error: ", shard.Shard.Writecache.ErrorDB)
cmd.Println(" Writecache FSTree path: ", shard.Shard.Writecache.PathFSTree)
cmd.Println(" Writecache FSTree error: ", shard.Shard.Writecache.ErrorFSTree)
}

}
1 change: 1 addition & 0 deletions cmd/neofs-lens/internal/storage/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ var Root = &cobra.Command{
func init() {
Root.AddCommand(
storageInspectObjCMD,
storageStatusObjCMD,
)
}

Expand Down
34 changes: 34 additions & 0 deletions cmd/neofs-lens/internal/storage/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package storage

import (
common "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/spf13/cobra"
)

var storageStatusObjCMD = &cobra.Command{
Use: "status",
Short: "Get object from the NeoFS node's storage snapshot",
Long: "Get object from the NeoFS node's storage snapshot",
Args: cobra.NoArgs,
Run: statusObject,
}

func init() {
common.AddAddressFlag(storageStatusObjCMD, &vAddress)
common.AddConfigFileFlag(storageStatusObjCMD, &vConfig)
}

func statusObject(cmd *cobra.Command, _ []string) {
var addr oid.Address

err := addr.DecodeString(vAddress)
common.ExitOnErr(cmd, common.Errf("invalid address argument: %w", err))

storage := openEngine(cmd)
defer storage.Close()
status, err := storage.ObjectStatus(addr)
common.ExitOnErr(cmd, common.Errf("could not fetch object: %w", err))

common.PrintStorageObjectStatus(cmd, status)
}
35 changes: 35 additions & 0 deletions pkg/local_object_storage/blobstor/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package blobstor

import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/common"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)

type ObjectSubstorageStatus struct {
Type string
Path string
Error error
}
type ObjectStatus struct {
//State ObjectState // LOCKED, INHUMED, GARBAGE, etc.
Substorages []ObjectSubstorageStatus
}

func (b *BlobStor) ObjectStatus(address oid.Address) (ObjectStatus, error) {
b.modeMtx.RLock()
defer b.modeMtx.RUnlock()
res := ObjectStatus{
Substorages: make([]ObjectSubstorageStatus, len(b.storage)),
}
prm := common.GetPrm{
Address: address,
}
for i := range b.storage {
_, err := b.storage[i].Storage.Get(prm)
res.Substorages[i].Error = err
res.Substorages[i].Type = b.storage[i].Storage.Type()
res.Substorages[i].Path = b.storage[i].Storage.Path()
}
return res, nil

}
37 changes: 37 additions & 0 deletions pkg/local_object_storage/engine/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package engine

import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/shard"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)

type ObjectShardStatus struct {
ID string
Shard shard.ObjectStatus
}

type ObjectStatus struct {
Shards []ObjectShardStatus
}

func (e *StorageEngine) ObjectStatus(address oid.Address) (ObjectStatus, error) {
var res ObjectStatus
var err error

e.iterateOverSortedShards(address, func(_ int, sh hashedShard) (stop bool) {
var shardStatus shard.ObjectStatus
shardStatus, err = sh.ObjectStatus(address)
id := *sh.ID()
res.Shards = append(res.Shards, ObjectShardStatus{
ID: id.String(),
Shard: shardStatus,
})

if err != nil {
return true
}
return false
})

return res, err
}
69 changes: 69 additions & 0 deletions pkg/local_object_storage/metabase/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package meta

import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"go.etcd.io/bbolt"
)

type ObjectStatus struct {
State []string
Path string
StorageID string
Error error
}

func (db *DB) ObjectStatus(address oid.Address) (ObjectStatus, error) {
db.modeMtx.RLock()
defer db.modeMtx.RUnlock()

var res ObjectStatus
var err error

if db.mode.NoMetabase() {
res.Error = ErrDegradedMode
return res, ErrDegradedMode
}

res.Path = db.boltDB.Path()

storageID := StorageIDPrm{}
storageID.SetAddress(address)
resStorageID, err := db.StorageID(storageID)
if id := resStorageID.StorageID(); id != nil {
res.StorageID = blobovnicza.NewIDFromBytes(id).String()
}

err = db.boltDB.View(func(tx *bbolt.Tx) error {
oID := address.Object()
cID := address.Container()
objKey := objectKey(address.Object(), make([]byte, objectKeySize))
key := make([]byte, bucketKeySize)

if objectLocked(tx, cID, oID) {
res.State = append(res.State, "LOCKED")
}
if inBucket(tx, primaryBucketName(cID, key), objKey) || inBucket(tx, parentBucketName(cID, key), objKey) {
res.State = append(res.State, "AVAILABLE")
}

graveyardBkt := tx.Bucket(graveyardBucketName)
garbageBkt := tx.Bucket(garbageBucketName)
addrKey := addressKey(address, make([]byte, addressKeySize))

removedStatus := inGraveyardWithKey(addrKey, graveyardBkt, garbageBkt)
if removedStatus != 0 && objectLocked(tx, cID, oID) {
res.State = append(res.State, "AVAILABLE")
}
if removedStatus == 1 {
res.State = append(res.State, "GC MARKED")
} else if removedStatus == 2 {
res.State = append(res.State, "IN GRAVEYARD")
} else {
res.State = append(res.State, "NOT IN GRAVEYARD")
}
return err
})
res.Error = err
return res, err
}
33 changes: 33 additions & 0 deletions pkg/local_object_storage/shard/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package shard

import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor"
meta "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/metabase"
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)

type ObjectStatus struct {
Blob blobstor.ObjectStatus
Metabase meta.ObjectStatus
Writecache writecache.ObjectStatus
Errors []error
}

func (s *Shard) ObjectStatus(address oid.Address) (ObjectStatus, error) {
var res ObjectStatus
var err error
res.Blob, err = s.blobStor.ObjectStatus(address)
res.Errors = append(res.Errors, err)
res.Metabase, err = s.metaBase.ObjectStatus(address)
res.Errors = append(res.Errors, err)
if s.hasWriteCache() {
res.Writecache, err = s.writeCache.ObjectStatus(address)
res.Errors = append(res.Errors, err)
}
if err != nil {
//TODO add context
return res, err
}
return res, err
}
41 changes: 41 additions & 0 deletions pkg/local_object_storage/writecache/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package writecache

import (
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobstor/common"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/pkg/errors"
"go.etcd.io/bbolt"
)

type ObjectStatus struct {
PathDB string
PathFSTree string
ErrorDB error
ErrorFSTree error
}

func (c *cache) ObjectStatus(address oid.Address) (ObjectStatus, error) {
saddr := address.EncodeToString()
var value []byte
var res ObjectStatus

err := c.db.View(func(tx *bbolt.Tx) error {
res.PathDB = c.db.Path()
b := tx.Bucket(defaultBucket)
if b == nil {
res.ErrorDB = errors.New("bucket not found")
} else {
value = b.Get([]byte(saddr))
if value == nil {
res.ErrorDB = errors.New("object not found")
}
}
return nil
})
_, err = c.fsTree.Get(common.GetPrm{Address: address})
res.PathFSTree = c.fsTree.Path()
if err != nil {
res.ErrorFSTree = errors.New("object not found")
}
return res, nil
}
1 change: 1 addition & 0 deletions pkg/local_object_storage/writecache/writecache.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Cache interface {
Init() error
Open(readOnly bool) error
Close() error
ObjectStatus(address oid.Address) (ObjectStatus, error)
}

type cache struct {
Expand Down

0 comments on commit 6163fa2

Please sign in to comment.