diff --git a/cmd/neofs-lens/internal/blobovnicza/inspect.go b/cmd/neofs-lens/internal/blobovnicza/inspect.go new file mode 100644 index 00000000..db9601cc --- /dev/null +++ b/cmd/neofs-lens/internal/blobovnicza/inspect.go @@ -0,0 +1,53 @@ +package blobovnicza + +import ( + common "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal" + "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza" + "github.com/nspcc-dev/neofs-sdk-go/object" + oid "github.com/nspcc-dev/neofs-sdk-go/object/id" + "github.com/spf13/cobra" +) + +var inspectCMD = &cobra.Command{ + Use: "inspect", + Short: "Object inspection", + Long: `Inspect specific object in a blobovnicza.`, + Run: inspectFunc, +} + +func init() { + common.AddAddressFlag(inspectCMD, &vAddress) + common.AddComponentPathFlag(inspectCMD, &vPath) + common.AddOutputFileFlag(inspectCMD, &vOut) +} + +func inspectFunc(cmd *cobra.Command, _ []string) { + var addr oid.Address + + err := addr.DecodeString(vAddress) + common.ExitOnErr(cmd, common.Errf("invalid address argument: %w", err)) + + blz := blobovnicza.New( + blobovnicza.WithPath(vPath), + blobovnicza.WithReadOnly(true), + ) + common.ExitOnErr(cmd, blz.Open()) + + defer blz.Close() + + var prm blobovnicza.GetPrm + prm.SetAddress(addr) + + res, err := blz.Get(prm) + common.ExitOnErr(cmd, common.Errf("could not fetch object: %w", err)) + + data := res.Object() + + var o object.Object + common.ExitOnErr(cmd, common.Errf("could not unmarshal object: %w", + o.Unmarshal(data)), + ) + + common.PrintObjectHeader(cmd, o) + common.WriteObjectToFile(cmd, vOut, data) +} diff --git a/cmd/neofs-lens/internal/blobovnicza/list.go b/cmd/neofs-lens/internal/blobovnicza/list.go new file mode 100644 index 00000000..54b3c785 --- /dev/null +++ b/cmd/neofs-lens/internal/blobovnicza/list.go @@ -0,0 +1,44 @@ +package blobovnicza + +import ( + "fmt" + "io" + + common "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal" + "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza" + oid "github.com/nspcc-dev/neofs-sdk-go/object/id" + "github.com/spf13/cobra" +) + +var listCMD = &cobra.Command{ + Use: "list", + Short: "Object listing", + Long: `List all objects stored in a blobovnicza.`, + Run: listFunc, +} + +func init() { + common.AddComponentPathFlag(listCMD, &vPath) +} + +func listFunc(cmd *cobra.Command, _ []string) { + // other targets can be supported + w := cmd.OutOrStderr() + + wAddr := func(addr oid.Address) error { + _, err := io.WriteString(w, fmt.Sprintf("%s\n", addr)) + return err + } + + blz := blobovnicza.New( + blobovnicza.WithPath(vPath), + blobovnicza.WithReadOnly(true), + ) + + common.ExitOnErr(cmd, blz.Open()) + + defer blz.Close() + + err := blobovnicza.IterateAddresses(blz, wAddr) + common.ExitOnErr(cmd, common.Errf("blobovnicza iterator failure: %w", err)) +} diff --git a/cmd/neofs-lens/internal/blobovnicza/root.go b/cmd/neofs-lens/internal/blobovnicza/root.go new file mode 100644 index 00000000..aa82c251 --- /dev/null +++ b/cmd/neofs-lens/internal/blobovnicza/root.go @@ -0,0 +1,19 @@ +package blobovnicza + +import "github.com/spf13/cobra" + +var ( + vAddress string + vPath string + vOut string +) + +// Root contains `blobovnicza` command definition. +var Root = &cobra.Command{ + Use: "blobovnicza", + Short: "Operations with a blobovnicza", +} + +func init() { + Root.AddCommand(listCMD, inspectCMD) +} diff --git a/cmd/neofs-lens/internal/commands/inspect/inspect.go b/cmd/neofs-lens/internal/commands/inspect/inspect.go deleted file mode 100644 index 80c5e881..00000000 --- a/cmd/neofs-lens/internal/commands/inspect/inspect.go +++ /dev/null @@ -1,145 +0,0 @@ -package inspect - -import ( - "fmt" - "os" - - common "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal" - "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza" - "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache" - 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" - "github.com/spf13/cobra" -) - -const ( - flagAddress = "address" - flagEnginePath = "path" - flagHeader = "header" - flagOutFile = "out" - flagWriteCache = "writecache" -) - -var ( - vAddress string - vHeader bool - vPath string - vOut string - vWriteCache bool -) - -// Command contains `inspect` command definition. -var Command = &cobra.Command{ - Use: "inspect", - Short: "Object inspection", - Long: `Inspect specific object in storage engine component.`, - Run: objectInspectCmd, -} - -func init() { - Command.Flags().StringVar(&vAddress, flagAddress, "", "Object address") - _ = Command.MarkFlagRequired(flagAddress) - - Command.Flags().StringVar(&vPath, flagEnginePath, "", - "Path to storage engine component", - ) - _ = Command.MarkFlagFilename(flagEnginePath) - _ = Command.MarkFlagRequired(flagEnginePath) - - Command.Flags().StringVar(&vOut, flagOutFile, "", - "File to save object payload") - - Command.Flags().BoolVar(&vHeader, flagHeader, false, "Inspect only header") - Command.Flags().BoolVar(&vWriteCache, flagWriteCache, false, - "Process write-cache") -} - -func objectInspectCmd(cmd *cobra.Command, _ []string) { - var addr oid.Address - - err := addr.DecodeString(vAddress) - common.ExitOnErr(cmd, common.Errf("invalid address argument: %w", err)) - - if vOut == "" && !vHeader { - common.ExitOnErr(cmd, fmt.Errorf("either --%s or --%s flag must be provided", - flagHeader, flagOutFile)) - } - - if vWriteCache { - db, err := writecache.OpenDB(vPath, true) - common.ExitOnErr(cmd, common.Errf("could not open write-cache db: %w", err)) - - defer db.Close() - - data, err := writecache.Get(db, []byte(vAddress)) - common.ExitOnErr(cmd, common.Errf("could not fetch object: %w", err)) - printObjectInfo(cmd, data) - return - } - - blz := blobovnicza.New( - blobovnicza.WithPath(vPath), - blobovnicza.WithReadOnly(true)) - common.ExitOnErr(cmd, blz.Open()) - - defer blz.Close() - - var prm blobovnicza.GetPrm - prm.SetAddress(addr) - res, err := blz.Get(prm) - common.ExitOnErr(cmd, common.Errf("could not fetch object: %w", err)) - - printObjectInfo(cmd, res.Object()) -} - -func printContainerID(cmd *cobra.Command, recv func() (cid.ID, bool)) { - var val string - - id, ok := recv() - if ok { - val = id.String() - } else { - val = "" - } - - cmd.Println("CID:", val) -} - -func printObjectID(cmd *cobra.Command, recv func() (oid.ID, bool)) { - var val string - - id, ok := recv() - if ok { - val = id.String() - } else { - val = "" - } - - cmd.Println("ID:", val) -} - -func printObjectInfo(cmd *cobra.Command, data []byte) { - obj := object.New() - err := obj.Unmarshal(data) - common.ExitOnErr(cmd, common.Errf("can't unmarshal object: %w", err)) - - if vHeader { - cmd.Println("Version:", obj.Version()) - cmd.Println("Type:", obj.Type()) - printContainerID(cmd, obj.ContainerID) - printObjectID(cmd, obj.ID) - cmd.Println("Owner:", obj.OwnerID()) - cmd.Println("CreatedAt:", obj.CreationEpoch()) - cmd.Println("PayloadSize:", obj.PayloadSize()) - cmd.Println("Attributes:") - for _, attr := range obj.Attributes() { - cmd.Printf(" %s: %s\n", attr.Key(), attr.Value()) - } - } - - if vOut != "" { - err := os.WriteFile(vOut, obj.Payload(), 0644) - common.ExitOnErr(cmd, common.Errf("couldn't write payload: %w", err)) - } -} diff --git a/cmd/neofs-lens/internal/commands/list/list.go b/cmd/neofs-lens/internal/commands/list/list.go deleted file mode 100644 index 8332acf3..00000000 --- a/cmd/neofs-lens/internal/commands/list/list.go +++ /dev/null @@ -1,73 +0,0 @@ -package cmdlist - -import ( - "fmt" - "io" - - common "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal" - "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/blobovnicza" - "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache" - oid "github.com/nspcc-dev/neofs-sdk-go/object/id" - "github.com/spf13/cobra" -) - -const ( - flagFile = "path" - flagWriteCache = "writecache" -) - -var ( - vPath string - vWriteCache bool -) - -func init() { - Command.Flags().StringVar(&vPath, flagFile, "", - "Path to storage engine component", - ) - _ = Command.MarkFlagFilename(flagFile) - _ = Command.MarkFlagRequired(flagFile) - - Command.Flags().BoolVar(&vWriteCache, flagWriteCache, false, - "Process write-cache", - ) -} - -var Command = &cobra.Command{ - Use: "list", - Short: "Object listing", - Long: `List all objects stored in storage engine component.`, - Run: func(cmd *cobra.Command, args []string) { - // other targets can be supported - w := cmd.OutOrStderr() - - wAddr := func(addr oid.Address) error { - _, err := io.WriteString(w, fmt.Sprintf("%s\n", addr)) - return err - } - - if vWriteCache { - db, err := writecache.OpenDB(vPath, true) - common.ExitOnErr(cmd, common.Errf("could not open write-cache db: %w", err)) - - defer db.Close() - - err = writecache.IterateDB(db, wAddr) - common.ExitOnErr(cmd, common.Errf("write-cache iterator failure: %w", err)) - - return - } - - blz := blobovnicza.New( - blobovnicza.WithPath(vPath), - blobovnicza.WithReadOnly(true), - ) - - common.ExitOnErr(cmd, blz.Open()) - - defer blz.Close() - - err := blobovnicza.IterateAddresses(blz, wAddr) - common.ExitOnErr(cmd, common.Errf("blobovnicza iterator failure: %w", err)) - }, -} diff --git a/cmd/neofs-lens/internal/common.go b/cmd/neofs-lens/internal/errors.go similarity index 100% rename from cmd/neofs-lens/internal/common.go rename to cmd/neofs-lens/internal/errors.go diff --git a/cmd/neofs-lens/internal/flags.go b/cmd/neofs-lens/internal/flags.go new file mode 100644 index 00000000..8a987a2d --- /dev/null +++ b/cmd/neofs-lens/internal/flags.go @@ -0,0 +1,35 @@ +package common + +import ( + "github.com/spf13/cobra" +) + +const ( + flagAddress = "address" + flagEnginePath = "path" + flagOutFile = "out" +) + +// AddAddressFlag adds the address flag to the passed cobra command. +func AddAddressFlag(cmd *cobra.Command, v *string) { + cmd.Flags().StringVar(v, flagAddress, "", "Object address") + _ = cmd.MarkFlagRequired(flagAddress) +} + +// AddComponentPathFlag adds the path-to-component flag to the +// passed cobra command. +func AddComponentPathFlag(cmd *cobra.Command, v *string) { + cmd.Flags().StringVar(v, flagEnginePath, "", + "Path to storage engine component", + ) + _ = cmd.MarkFlagFilename(flagEnginePath) + _ = cmd.MarkFlagRequired(flagEnginePath) +} + +// AddOutputFileFlag adds the output file flag to the passed cobra +// command. +func AddOutputFileFlag(cmd *cobra.Command, v *string) { + cmd.Flags().StringVar(v, flagOutFile, "", + "File to save object payload") + _ = cmd.MarkFlagFilename(flagOutFile) +} diff --git a/cmd/neofs-lens/internal/printers.go b/cmd/neofs-lens/internal/printers.go new file mode 100644 index 00000000..d530132f --- /dev/null +++ b/cmd/neofs-lens/internal/printers.go @@ -0,0 +1,65 @@ +package common + +import ( + "os" + + 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" + "github.com/spf13/cobra" +) + +// PrintObjectHeader prints passed object's header fields via +// the passed cobra command. Does nothing with the payload. +func PrintObjectHeader(cmd *cobra.Command, h object.Object) { + cmd.Println("Version:", h.Version()) + cmd.Println("Type:", h.Type()) + printContainerID(cmd, h.ContainerID) + printObjectID(cmd, h.ID) + cmd.Println("Owner:", h.OwnerID()) + cmd.Println("CreatedAt:", h.CreationEpoch()) + cmd.Println("PayloadSize:", h.PayloadSize()) + cmd.Println("Attributes:") + for _, attr := range h.Attributes() { + cmd.Printf(" %s: %s\n", attr.Key(), attr.Value()) + } +} + +func printContainerID(cmd *cobra.Command, recv func() (cid.ID, bool)) { + var val string + + id, ok := recv() + if ok { + val = id.String() + } else { + val = "" + } + + cmd.Println("CID:", val) +} + +func printObjectID(cmd *cobra.Command, recv func() (oid.ID, bool)) { + var val string + + id, ok := recv() + if ok { + val = id.String() + } else { + val = "" + } + + cmd.Println("ID:", val) +} + +// WriteObjectToFile writes object to the provided path. Does nothing if +// the path is empty. +func WriteObjectToFile(cmd *cobra.Command, path string, data []byte) { + if path == "" { + return + } + + ExitOnErr(cmd, Errf("could not write file: %w", + os.WriteFile(path, data, 0644))) + + cmd.Printf("\nSaved payload to '%s' file\n", path) +} diff --git a/cmd/neofs-lens/internal/writecache/inspect.go b/cmd/neofs-lens/internal/writecache/inspect.go new file mode 100644 index 00000000..1f5ef7ff --- /dev/null +++ b/cmd/neofs-lens/internal/writecache/inspect.go @@ -0,0 +1,37 @@ +package writecache + +import ( + common "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal" + "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache" + "github.com/nspcc-dev/neofs-sdk-go/object" + "github.com/spf13/cobra" +) + +var inspectCMD = &cobra.Command{ + Use: "inspect", + Short: "Object inspection", + Long: `Inspect specific object in a write-cache.`, + Run: inspectFunc, +} + +func init() { + common.AddAddressFlag(inspectCMD, &vAddress) + common.AddComponentPathFlag(inspectCMD, &vPath) + common.AddOutputFileFlag(inspectCMD, &vOut) +} + +func inspectFunc(cmd *cobra.Command, _ []string) { + db, err := writecache.OpenDB(vPath, true) + common.ExitOnErr(cmd, common.Errf("could not open write-cache db: %w", err)) + + defer db.Close() + + data, err := writecache.Get(db, []byte(vAddress)) + common.ExitOnErr(cmd, common.Errf("could not fetch object: %w", err)) + + var o object.Object + common.ExitOnErr(cmd, common.Errf("could not unmarshal object: %w", o.Unmarshal(data))) + + common.PrintObjectHeader(cmd, o) + common.WriteObjectToFile(cmd, vOut, data) +} diff --git a/cmd/neofs-lens/internal/writecache/list.go b/cmd/neofs-lens/internal/writecache/list.go new file mode 100644 index 00000000..2da1c083 --- /dev/null +++ b/cmd/neofs-lens/internal/writecache/list.go @@ -0,0 +1,40 @@ +package writecache + +import ( + "fmt" + "io" + + common "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal" + "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/writecache" + oid "github.com/nspcc-dev/neofs-sdk-go/object/id" + "github.com/spf13/cobra" +) + +var listCMD = &cobra.Command{ + Use: "inspect", + Short: "Object inspection", + Long: `Inspect specific object in a write-cache.`, + Run: listFunc, +} + +func init() { + common.AddComponentPathFlag(listCMD, &vPath) +} + +func listFunc(cmd *cobra.Command, _ []string) { + // other targets can be supported + w := cmd.OutOrStderr() + + wAddr := func(addr oid.Address) error { + _, err := io.WriteString(w, fmt.Sprintf("%s\n", addr)) + return err + } + + db, err := writecache.OpenDB(vPath, true) + common.ExitOnErr(cmd, common.Errf("could not open write-cache db: %w", err)) + + defer db.Close() + + err = writecache.IterateDB(db, wAddr) + common.ExitOnErr(cmd, common.Errf("write-cache iterator failure: %w", err)) +} diff --git a/cmd/neofs-lens/internal/writecache/root.go b/cmd/neofs-lens/internal/writecache/root.go new file mode 100644 index 00000000..493a787e --- /dev/null +++ b/cmd/neofs-lens/internal/writecache/root.go @@ -0,0 +1,19 @@ +package writecache + +import "github.com/spf13/cobra" + +var ( + vAddress string + vPath string + vOut string +) + +// Root contains `write-cache` command definition. +var Root = &cobra.Command{ + Use: "write-cache", + Short: "Operations with write-cache", +} + +func init() { + Root.AddCommand(listCMD, inspectCMD) +} diff --git a/cmd/neofs-lens/root.go b/cmd/neofs-lens/root.go index c875b6d0..96f1193a 100644 --- a/cmd/neofs-lens/root.go +++ b/cmd/neofs-lens/root.go @@ -3,8 +3,8 @@ package main import ( "os" - "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal/commands/inspect" - cmdlist "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal/commands/list" + "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal/blobovnicza" + "github.com/nspcc-dev/neofs-node/cmd/neofs-lens/internal/writecache" "github.com/nspcc-dev/neofs-node/misc" "github.com/nspcc-dev/neofs-node/pkg/util/gendoc" "github.com/spf13/cobra" @@ -34,8 +34,8 @@ func init() { command.SetOut(os.Stdout) command.Flags().Bool("version", false, "application version") command.AddCommand( - cmdlist.Command, - inspect.Command, + blobovnicza.Root, + writecache.Root, gendoc.Command(command), ) }