forked from TrueCloudLab/frostfs-node
[#1383] neofs-cli: move object
command to a separate package
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
12bc5607f7
commit
a219e3a667
15 changed files with 1237 additions and 1190 deletions
|
@ -1,11 +1,14 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/checksum"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,3 +31,17 @@ func PrettyPrintUnixTime(s string) string {
|
||||||
|
|
||||||
return timestamp.String()
|
return timestamp.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrintChecksum prints checksum.
|
||||||
|
func PrintChecksum(cmd *cobra.Command, name string, recv func() (checksum.Checksum, bool)) {
|
||||||
|
var strVal string
|
||||||
|
|
||||||
|
cs, csSet := recv()
|
||||||
|
if csSet {
|
||||||
|
strVal = hex.EncodeToString(cs.Value())
|
||||||
|
} else {
|
||||||
|
strVal = "<empty>"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Printf("%s: %s\n", name, strVal)
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
|
||||||
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/container"
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
@ -286,10 +288,11 @@ var listContainerObjectsCmd = &cobra.Command{
|
||||||
filters := new(object.SearchFilters)
|
filters := new(object.SearchFilters)
|
||||||
filters.AddRootFilter() // search only user created objects
|
filters.AddRootFilter() // search only user created objects
|
||||||
|
|
||||||
var prm internalclient.SearchObjectsPrm
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
prepareSessionPrm(cmd, *id, nil, &prm)
|
var prm internalclient.SearchObjectsPrm
|
||||||
prepareObjectPrm(cmd, &prm)
|
sessionCli.Prepare(cmd, *id, nil, pk, &prm)
|
||||||
|
objectCli.Prepare(cmd, &prm)
|
||||||
prm.SetContainerID(*id)
|
prm.SetContainerID(*id)
|
||||||
prm.SetFilters(*filters)
|
prm.SetFilters(*filters)
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
54
cmd/neofs-cli/modules/object/delete.go
Normal file
54
cmd/neofs-cli/modules/object/delete.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var objectDelCmd = &cobra.Command{
|
||||||
|
Use: "delete",
|
||||||
|
Aliases: []string{"del"},
|
||||||
|
Short: "Delete object from NeoFS",
|
||||||
|
Long: "Delete object from NeoFS",
|
||||||
|
Run: deleteObject,
|
||||||
|
}
|
||||||
|
|
||||||
|
func initObjectDeleteCmd() {
|
||||||
|
commonflags.Init(objectDelCmd)
|
||||||
|
commonflags.InitSession(objectDelCmd)
|
||||||
|
|
||||||
|
flags := objectDelCmd.Flags()
|
||||||
|
|
||||||
|
flags.String("cid", "", "Container ID")
|
||||||
|
_ = objectDelCmd.MarkFlagRequired("cid")
|
||||||
|
|
||||||
|
flags.String("oid", "", "Object ID")
|
||||||
|
_ = objectDelCmd.MarkFlagRequired("oid")
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteObject(cmd *cobra.Command, _ []string) {
|
||||||
|
var cnr cid.ID
|
||||||
|
var obj oid.ID
|
||||||
|
|
||||||
|
objAddr := readObjectAddress(cmd, &cnr, &obj)
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
|
var prm internalclient.DeleteObjectPrm
|
||||||
|
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm)
|
||||||
|
Prepare(cmd, &prm)
|
||||||
|
prm.SetAddress(objAddr)
|
||||||
|
|
||||||
|
res, err := internalclient.DeleteObject(prm)
|
||||||
|
common.ExitOnErr(cmd, "rpc error: %w", err)
|
||||||
|
|
||||||
|
tomb := res.Tombstone()
|
||||||
|
|
||||||
|
cmd.Println("Object removed successfully.")
|
||||||
|
cmd.Printf(" ID: %s\n CID: %s\n", tomb, cnr)
|
||||||
|
}
|
121
cmd/neofs-cli/modules/object/get.go
Normal file
121
cmd/neofs-cli/modules/object/get.go
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/cheggaaa/pb"
|
||||||
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
var objectGetCmd = &cobra.Command{
|
||||||
|
Use: "get",
|
||||||
|
Short: "Get object from NeoFS",
|
||||||
|
Long: "Get object from NeoFS",
|
||||||
|
Run: getObject,
|
||||||
|
}
|
||||||
|
|
||||||
|
func initObjectGetCmd() {
|
||||||
|
commonflags.Init(objectGetCmd)
|
||||||
|
commonflags.InitSession(objectGetCmd)
|
||||||
|
|
||||||
|
flags := objectGetCmd.Flags()
|
||||||
|
|
||||||
|
flags.String("cid", "", "Container ID")
|
||||||
|
_ = objectGetCmd.MarkFlagRequired("cid")
|
||||||
|
|
||||||
|
flags.String("oid", "", "Object ID")
|
||||||
|
_ = objectGetCmd.MarkFlagRequired("oid")
|
||||||
|
|
||||||
|
flags.String("file", "", "File to write object payload to. Default: stdout.")
|
||||||
|
flags.String("header", "", "File to write header to. Default: stdout.")
|
||||||
|
flags.Bool(rawFlag, false, rawFlagDesc)
|
||||||
|
flags.Bool(noProgressFlag, false, "Do not show progress bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getObject(cmd *cobra.Command, _ []string) {
|
||||||
|
var cnr cid.ID
|
||||||
|
var obj oid.ID
|
||||||
|
|
||||||
|
objAddr := readObjectAddress(cmd, &cnr, &obj)
|
||||||
|
|
||||||
|
var out io.Writer
|
||||||
|
filename := cmd.Flag("file").Value.String()
|
||||||
|
if filename == "" {
|
||||||
|
out = os.Stdout
|
||||||
|
} else {
|
||||||
|
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
common.ExitOnErr(cmd, "", fmt.Errorf("can't open file '%s': %w", filename, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
out = f
|
||||||
|
}
|
||||||
|
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
|
var prm internalclient.GetObjectPrm
|
||||||
|
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm)
|
||||||
|
Prepare(cmd, &prm)
|
||||||
|
|
||||||
|
raw, _ := cmd.Flags().GetBool(rawFlag)
|
||||||
|
prm.SetRawFlag(raw)
|
||||||
|
prm.SetAddress(objAddr)
|
||||||
|
|
||||||
|
var p *pb.ProgressBar
|
||||||
|
noProgress, _ := cmd.Flags().GetBool(noProgressFlag)
|
||||||
|
|
||||||
|
if filename == "" || noProgress {
|
||||||
|
prm.SetPayloadWriter(out)
|
||||||
|
} else {
|
||||||
|
p = pb.New64(0)
|
||||||
|
p.Output = cmd.OutOrStdout()
|
||||||
|
prm.SetPayloadWriter(p.NewProxyWriter(out))
|
||||||
|
prm.SetHeaderCallback(func(o *object.Object) {
|
||||||
|
p.SetTotal64(int64(o.PayloadSize()))
|
||||||
|
p.Start()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := internalclient.GetObject(prm)
|
||||||
|
if err != nil {
|
||||||
|
if ok := printSplitInfoErr(cmd, err); ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
common.ExitOnErr(cmd, "rpc error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hdrFile := cmd.Flag("header").Value.String()
|
||||||
|
if filename != "" {
|
||||||
|
if p != nil {
|
||||||
|
p.Finish()
|
||||||
|
}
|
||||||
|
if hdrFile != "" || !strictOutput(cmd) {
|
||||||
|
cmd.Printf("[%s] Object successfully saved\n", filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print header only if file is not streamed to stdout.
|
||||||
|
if filename != "" || hdrFile != "" {
|
||||||
|
err = saveAndPrintHeader(cmd, res.Header(), hdrFile)
|
||||||
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func strictOutput(cmd *cobra.Command) bool {
|
||||||
|
toJSON, _ := cmd.Flags().GetBool("json")
|
||||||
|
toProto, _ := cmd.Flags().GetBool("proto")
|
||||||
|
return toJSON || toProto
|
||||||
|
}
|
128
cmd/neofs-cli/modules/object/hash.go
Normal file
128
cmd/neofs-cli/modules/object/hash.go
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/checksum"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
const getRangeHashSaltFlag = "salt"
|
||||||
|
|
||||||
|
const (
|
||||||
|
hashSha256 = "sha256"
|
||||||
|
hashTz = "tz"
|
||||||
|
rangeSep = ":"
|
||||||
|
)
|
||||||
|
|
||||||
|
var objectHashCmd = &cobra.Command{
|
||||||
|
Use: "hash",
|
||||||
|
Short: "Get object hash",
|
||||||
|
Long: "Get object hash",
|
||||||
|
Run: getObjectHash,
|
||||||
|
}
|
||||||
|
|
||||||
|
func initObjectHashCmd() {
|
||||||
|
commonflags.Init(objectHashCmd)
|
||||||
|
|
||||||
|
flags := objectHashCmd.Flags()
|
||||||
|
|
||||||
|
flags.String("cid", "", "Container ID")
|
||||||
|
_ = objectHashCmd.MarkFlagRequired("cid")
|
||||||
|
|
||||||
|
flags.String("oid", "", "Object ID")
|
||||||
|
_ = objectHashCmd.MarkFlagRequired("oid")
|
||||||
|
|
||||||
|
flags.String("range", "", "Range to take hash from in the form offset1:length1,...")
|
||||||
|
flags.String("type", hashSha256, "Hash type. Either 'sha256' or 'tz'")
|
||||||
|
flags.String(getRangeHashSaltFlag, "", "Salt in hex format")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getObjectHash(cmd *cobra.Command, _ []string) {
|
||||||
|
var cnr cid.ID
|
||||||
|
var obj oid.ID
|
||||||
|
|
||||||
|
objAddr := readObjectAddress(cmd, &cnr, &obj)
|
||||||
|
|
||||||
|
ranges, err := getRangeList(cmd)
|
||||||
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
typ, err := getHashType(cmd)
|
||||||
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
|
strSalt := strings.TrimPrefix(cmd.Flag(getRangeHashSaltFlag).Value.String(), "0x")
|
||||||
|
|
||||||
|
salt, err := hex.DecodeString(strSalt)
|
||||||
|
common.ExitOnErr(cmd, "could not decode salt: %w", err)
|
||||||
|
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
|
tz := typ == hashTz
|
||||||
|
fullHash := len(ranges) == 0
|
||||||
|
if fullHash {
|
||||||
|
var headPrm internalclient.HeadObjectPrm
|
||||||
|
sessionCli.Prepare(cmd, cnr, &obj, pk, &headPrm)
|
||||||
|
Prepare(cmd, &headPrm)
|
||||||
|
headPrm.SetAddress(objAddr)
|
||||||
|
|
||||||
|
// get hash of full payload through HEAD (may be user can do it through dedicated command?)
|
||||||
|
res, err := internalclient.HeadObject(headPrm)
|
||||||
|
common.ExitOnErr(cmd, "rpc error: %w", err)
|
||||||
|
|
||||||
|
var cs checksum.Checksum
|
||||||
|
var csSet bool
|
||||||
|
|
||||||
|
if tz {
|
||||||
|
cs, csSet = res.Header().PayloadHomomorphicHash()
|
||||||
|
} else {
|
||||||
|
cs, csSet = res.Header().PayloadChecksum()
|
||||||
|
}
|
||||||
|
|
||||||
|
if csSet {
|
||||||
|
cmd.Println(hex.EncodeToString(cs.Value()))
|
||||||
|
} else {
|
||||||
|
cmd.Println("Missing checksum in object header.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var hashPrm internalclient.HashPayloadRangesPrm
|
||||||
|
sessionCli.Prepare(cmd, cnr, &obj, pk, &hashPrm)
|
||||||
|
Prepare(cmd, &hashPrm)
|
||||||
|
hashPrm.SetAddress(objAddr)
|
||||||
|
hashPrm.SetSalt(salt)
|
||||||
|
hashPrm.SetRanges(ranges)
|
||||||
|
|
||||||
|
if tz {
|
||||||
|
hashPrm.TZ()
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := internalclient.HashPayloadRanges(hashPrm)
|
||||||
|
common.ExitOnErr(cmd, "rpc error: %w", err)
|
||||||
|
|
||||||
|
hs := res.HashList()
|
||||||
|
|
||||||
|
for i := range hs {
|
||||||
|
cmd.Printf("Offset=%d (Length=%d)\t: %s\n", ranges[i].GetOffset(), ranges[i].GetLength(),
|
||||||
|
hex.EncodeToString(hs[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHashType(cmd *cobra.Command) (string, error) {
|
||||||
|
rawType := cmd.Flag("type").Value.String()
|
||||||
|
switch typ := strings.ToLower(rawType); typ {
|
||||||
|
case hashSha256, hashTz:
|
||||||
|
return typ, nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("invalid hash type: %s", typ)
|
||||||
|
}
|
||||||
|
}
|
200
cmd/neofs-cli/modules/object/head.go
Normal file
200
cmd/neofs-cli/modules/object/head.go
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
|
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"
|
||||||
|
oidSDK "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var objectHeadCmd = &cobra.Command{
|
||||||
|
Use: "head",
|
||||||
|
Short: "Get object header",
|
||||||
|
Long: "Get object header",
|
||||||
|
Run: getObjectHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
func initObjectHeadCmd() {
|
||||||
|
commonflags.Init(objectHeadCmd)
|
||||||
|
commonflags.InitSession(objectHeadCmd)
|
||||||
|
|
||||||
|
flags := objectHeadCmd.Flags()
|
||||||
|
|
||||||
|
flags.String("cid", "", "Container ID")
|
||||||
|
_ = objectHeadCmd.MarkFlagRequired("cid")
|
||||||
|
|
||||||
|
flags.String("oid", "", "Object ID")
|
||||||
|
_ = objectHeadCmd.MarkFlagRequired("oid")
|
||||||
|
|
||||||
|
flags.String("file", "", "File to write header to. Default: stdout.")
|
||||||
|
flags.Bool("main-only", false, "Return only main fields")
|
||||||
|
flags.Bool("json", false, "Marshal output in JSON")
|
||||||
|
flags.Bool("proto", false, "Marshal output in Protobuf")
|
||||||
|
flags.Bool(rawFlag, false, rawFlagDesc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getObjectHeader(cmd *cobra.Command, _ []string) {
|
||||||
|
var cnr cid.ID
|
||||||
|
var obj oid.ID
|
||||||
|
|
||||||
|
objAddr := readObjectAddress(cmd, &cnr, &obj)
|
||||||
|
mainOnly, _ := cmd.Flags().GetBool("main-only")
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
|
var prm internalclient.HeadObjectPrm
|
||||||
|
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm)
|
||||||
|
Prepare(cmd, &prm)
|
||||||
|
|
||||||
|
raw, _ := cmd.Flags().GetBool(rawFlag)
|
||||||
|
prm.SetRawFlag(raw)
|
||||||
|
prm.SetAddress(objAddr)
|
||||||
|
prm.SetMainOnlyFlag(mainOnly)
|
||||||
|
|
||||||
|
res, err := internalclient.HeadObject(prm)
|
||||||
|
if err != nil {
|
||||||
|
if ok := printSplitInfoErr(cmd, err); ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
common.ExitOnErr(cmd, "rpc error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = saveAndPrintHeader(cmd, res.Header(), cmd.Flag("file").Value.String())
|
||||||
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveAndPrintHeader(cmd *cobra.Command, obj *object.Object, filename string) error {
|
||||||
|
bs, err := marshalHeader(cmd, obj)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not marshal header: %w", err)
|
||||||
|
}
|
||||||
|
if len(bs) != 0 {
|
||||||
|
if filename == "" {
|
||||||
|
cmd.Println(string(bs))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = os.WriteFile(filename, bs, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not write header to file: %w", err)
|
||||||
|
}
|
||||||
|
cmd.Printf("[%s] Header successfully saved.", filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
return printHeader(cmd, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalHeader(cmd *cobra.Command, hdr *object.Object) ([]byte, error) {
|
||||||
|
toJSON, _ := cmd.Flags().GetBool("json")
|
||||||
|
toProto, _ := cmd.Flags().GetBool("proto")
|
||||||
|
switch {
|
||||||
|
case toJSON && toProto:
|
||||||
|
return nil, errors.New("'--json' and '--proto' flags are mutually exclusive")
|
||||||
|
case toJSON:
|
||||||
|
return hdr.MarshalJSON()
|
||||||
|
case toProto:
|
||||||
|
return hdr.Marshal()
|
||||||
|
default:
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printObjectID(cmd *cobra.Command, recv func() (oidSDK.ID, bool)) {
|
||||||
|
var strID string
|
||||||
|
|
||||||
|
id, ok := recv()
|
||||||
|
if ok {
|
||||||
|
strID = id.String()
|
||||||
|
} else {
|
||||||
|
strID = "<empty>"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Printf("ID: %s\n", strID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printContainerID(cmd *cobra.Command, recv func() (cid.ID, bool)) {
|
||||||
|
var strID string
|
||||||
|
|
||||||
|
id, ok := recv()
|
||||||
|
if ok {
|
||||||
|
strID = id.String()
|
||||||
|
} else {
|
||||||
|
strID = "<empty>"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Printf("CID: %s\n", strID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHeader(cmd *cobra.Command, obj *object.Object) error {
|
||||||
|
printObjectID(cmd, obj.ID)
|
||||||
|
printContainerID(cmd, obj.ContainerID)
|
||||||
|
cmd.Printf("Owner: %s\n", obj.OwnerID())
|
||||||
|
cmd.Printf("CreatedAt: %d\n", obj.CreationEpoch())
|
||||||
|
cmd.Printf("Size: %d\n", obj.PayloadSize())
|
||||||
|
common.PrintChecksum(cmd, "HomoHash", obj.PayloadHomomorphicHash)
|
||||||
|
common.PrintChecksum(cmd, "Checksum", obj.PayloadChecksum)
|
||||||
|
cmd.Printf("Type: %s\n", obj.Type())
|
||||||
|
|
||||||
|
cmd.Println("Attributes:")
|
||||||
|
for _, attr := range obj.Attributes() {
|
||||||
|
if attr.Key() == object.AttributeTimestamp {
|
||||||
|
cmd.Printf(" %s=%s (%s)\n",
|
||||||
|
attr.Key(),
|
||||||
|
attr.Value(),
|
||||||
|
common.PrettyPrintUnixTime(attr.Value()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmd.Printf(" %s=%s\n", attr.Key(), attr.Value())
|
||||||
|
}
|
||||||
|
|
||||||
|
return printSplitHeader(cmd, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printSplitHeader(cmd *cobra.Command, obj *object.Object) error {
|
||||||
|
if splitID := obj.SplitID(); splitID != nil {
|
||||||
|
cmd.Printf("Split ID: %s\n", splitID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if oid, ok := obj.ParentID(); ok {
|
||||||
|
cmd.Printf("Split ParentID: %s\n", oid)
|
||||||
|
}
|
||||||
|
|
||||||
|
if prev, ok := obj.PreviousID(); ok {
|
||||||
|
cmd.Printf("Split PreviousID: %s\n", prev)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range obj.Children() {
|
||||||
|
cmd.Printf("Split ChildID: %s\n", child.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if signature := obj.Signature(); signature != nil {
|
||||||
|
cmd.Print("Split Header Signature:\n")
|
||||||
|
|
||||||
|
// TODO(@cthulhu-rider): #1387 implement and use another approach to avoid conversion
|
||||||
|
var sigV2 refs.Signature
|
||||||
|
signature.WriteToV2(&sigV2)
|
||||||
|
|
||||||
|
cmd.Printf(" public key: %s\n", hex.EncodeToString(sigV2.GetKey()))
|
||||||
|
cmd.Printf(" signature: %s\n", hex.EncodeToString(sigV2.GetSign()))
|
||||||
|
}
|
||||||
|
|
||||||
|
parent := obj.Parent()
|
||||||
|
if parent != nil {
|
||||||
|
cmd.Print("\nSplit Parent Header:\n")
|
||||||
|
|
||||||
|
return printHeader(cmd, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package cmd
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -11,11 +11,12 @@ import (
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// object lock command.
|
// object lock command.
|
||||||
var cmdObjectLock = &cobra.Command{
|
var objectLockCmd = &cobra.Command{
|
||||||
Use: "lock CONTAINER OBJECT...",
|
Use: "lock CONTAINER OBJECT...",
|
||||||
Short: "Lock object in container",
|
Short: "Lock object in container",
|
||||||
Long: "Lock object in container",
|
Long: "Lock object in container",
|
||||||
|
@ -37,22 +38,22 @@ var cmdObjectLock = &cobra.Command{
|
||||||
|
|
||||||
key := key.GetOrGenerate(cmd)
|
key := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
idOwner, err := getOwnerID(key)
|
var idOwner user.ID
|
||||||
common.ExitOnErr(cmd, "", err)
|
user.IDFromKey(&idOwner, key.PublicKey)
|
||||||
|
|
||||||
var lock object.Lock
|
var lock object.Lock
|
||||||
lock.WriteMembers(lockList)
|
lock.WriteMembers(lockList)
|
||||||
|
|
||||||
obj := object.New()
|
obj := object.New()
|
||||||
obj.SetContainerID(cnr)
|
obj.SetContainerID(cnr)
|
||||||
obj.SetOwnerID(idOwner)
|
obj.SetOwnerID(&idOwner)
|
||||||
obj.SetType(object.TypeLock)
|
obj.SetType(object.TypeLock)
|
||||||
obj.SetPayload(lock.Marshal())
|
obj.SetPayload(lock.Marshal())
|
||||||
|
|
||||||
var prm internalclient.PutObjectPrm
|
var prm internalclient.PutObjectPrm
|
||||||
|
|
||||||
sessionCli.Prepare(cmd, cnr, nil, key, &prm)
|
sessionCli.Prepare(cmd, cnr, nil, key, &prm)
|
||||||
prepareObjectPrm(cmd, &prm)
|
Prepare(cmd, &prm)
|
||||||
prm.SetHeader(obj)
|
prm.SetHeader(obj)
|
||||||
|
|
||||||
_, err = internalclient.PutObject(prm)
|
_, err = internalclient.PutObject(prm)
|
||||||
|
@ -63,5 +64,6 @@ var cmdObjectLock = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func initCommandObjectLock() {
|
func initCommandObjectLock() {
|
||||||
commonflags.Init(cmdObjectLock)
|
commonflags.Init(objectLockCmd)
|
||||||
|
commonflags.InitSession(objectLockCmd)
|
||||||
}
|
}
|
217
cmd/neofs-cli/modules/object/put.go
Normal file
217
cmd/neofs-cli/modules/object/put.go
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cheggaaa/pb"
|
||||||
|
objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||||
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
putExpiresOnFlag = "expires-on"
|
||||||
|
noProgressFlag = "no-progress"
|
||||||
|
notificationFlag = "notify"
|
||||||
|
)
|
||||||
|
|
||||||
|
var putExpiredOn uint64
|
||||||
|
|
||||||
|
var objectPutCmd = &cobra.Command{
|
||||||
|
Use: "put",
|
||||||
|
Short: "Put object to NeoFS",
|
||||||
|
Long: "Put object to NeoFS",
|
||||||
|
Run: putObject,
|
||||||
|
}
|
||||||
|
|
||||||
|
func initObjectPutCmd() {
|
||||||
|
commonflags.Init(objectPutCmd)
|
||||||
|
commonflags.InitSession(objectPutCmd)
|
||||||
|
|
||||||
|
flags := objectPutCmd.Flags()
|
||||||
|
|
||||||
|
flags.String("file", "", "File with object payload")
|
||||||
|
_ = objectPutCmd.MarkFlagFilename("file")
|
||||||
|
_ = objectPutCmd.MarkFlagRequired("file")
|
||||||
|
|
||||||
|
flags.String("cid", "", "Container ID")
|
||||||
|
_ = objectPutCmd.MarkFlagRequired("cid")
|
||||||
|
|
||||||
|
flags.String("attributes", "", "User attributes in form of Key1=Value1,Key2=Value2")
|
||||||
|
flags.Bool("disable-filename", false, "Do not set well-known filename attribute")
|
||||||
|
flags.Bool("disable-timestamp", false, "Do not set well-known timestamp attribute")
|
||||||
|
flags.Uint64VarP(&putExpiredOn, putExpiresOnFlag, "e", 0, "Last epoch in the life of the object")
|
||||||
|
flags.Bool(noProgressFlag, false, "Do not show progress bar")
|
||||||
|
|
||||||
|
flags.String(notificationFlag, "", "Object notification in the form of *epoch*:*topic*; '-' topic means using default")
|
||||||
|
}
|
||||||
|
|
||||||
|
func putObject(cmd *cobra.Command, _ []string) {
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
|
var ownerID user.ID
|
||||||
|
user.IDFromKey(&ownerID, pk.PublicKey)
|
||||||
|
|
||||||
|
var cnr cid.ID
|
||||||
|
readCID(cmd, &cnr)
|
||||||
|
|
||||||
|
filename := cmd.Flag("file").Value.String()
|
||||||
|
f, err := os.OpenFile(filename, os.O_RDONLY, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
common.ExitOnErr(cmd, "", fmt.Errorf("can't open file '%s': %w", filename, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs, err := parseObjectAttrs(cmd)
|
||||||
|
common.ExitOnErr(cmd, "can't parse object attributes: %w", err)
|
||||||
|
|
||||||
|
expiresOn, _ := cmd.Flags().GetUint64(putExpiresOnFlag)
|
||||||
|
if expiresOn > 0 {
|
||||||
|
var expAttrFound bool
|
||||||
|
expAttrValue := strconv.FormatUint(expiresOn, 10)
|
||||||
|
|
||||||
|
for i := range attrs {
|
||||||
|
if attrs[i].Key() == objectV2.SysAttributeExpEpoch {
|
||||||
|
attrs[i].SetValue(expAttrValue)
|
||||||
|
expAttrFound = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !expAttrFound {
|
||||||
|
index := len(attrs)
|
||||||
|
attrs = append(attrs, object.Attribute{})
|
||||||
|
attrs[index].SetKey(objectV2.SysAttributeExpEpoch)
|
||||||
|
attrs[index].SetValue(expAttrValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := object.New()
|
||||||
|
obj.SetContainerID(cnr)
|
||||||
|
obj.SetOwnerID(&ownerID)
|
||||||
|
obj.SetAttributes(attrs...)
|
||||||
|
|
||||||
|
notificationInfo, err := parseObjectNotifications(cmd)
|
||||||
|
common.ExitOnErr(cmd, "can't parse object notification information: %w", err)
|
||||||
|
|
||||||
|
if notificationInfo != nil {
|
||||||
|
obj.SetNotification(*notificationInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var prm internalclient.PutObjectPrm
|
||||||
|
sessionCli.Prepare(cmd, cnr, nil, pk, &prm)
|
||||||
|
Prepare(cmd, &prm)
|
||||||
|
prm.SetHeader(obj)
|
||||||
|
|
||||||
|
var p *pb.ProgressBar
|
||||||
|
|
||||||
|
noProgress, _ := cmd.Flags().GetBool(noProgressFlag)
|
||||||
|
if noProgress {
|
||||||
|
prm.SetPayloadReader(f)
|
||||||
|
} else {
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
cmd.PrintErrf("Failed to get file size, progress bar is disabled: %v\n", err)
|
||||||
|
prm.SetPayloadReader(f)
|
||||||
|
} else {
|
||||||
|
p = pb.New64(fi.Size())
|
||||||
|
p.Output = cmd.OutOrStdout()
|
||||||
|
prm.SetPayloadReader(p.NewProxyReader(f))
|
||||||
|
p.Start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := internalclient.PutObject(prm)
|
||||||
|
common.ExitOnErr(cmd, "rpc error: %w", err)
|
||||||
|
|
||||||
|
if p != nil {
|
||||||
|
p.Finish()
|
||||||
|
}
|
||||||
|
cmd.Printf("[%s] Object successfully stored\n", filename)
|
||||||
|
cmd.Printf(" ID: %s\n CID: %s\n", res.ID(), cnr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseObjectAttrs(cmd *cobra.Command) ([]object.Attribute, error) {
|
||||||
|
var rawAttrs []string
|
||||||
|
|
||||||
|
raw := cmd.Flag("attributes").Value.String()
|
||||||
|
if len(raw) != 0 {
|
||||||
|
rawAttrs = strings.Split(raw, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs := make([]object.Attribute, len(rawAttrs), len(rawAttrs)+2) // name + timestamp attributes
|
||||||
|
for i := range rawAttrs {
|
||||||
|
kv := strings.SplitN(rawAttrs[i], "=", 2)
|
||||||
|
if len(kv) != 2 {
|
||||||
|
return nil, fmt.Errorf("invalid attribute format: %s", rawAttrs[i])
|
||||||
|
}
|
||||||
|
attrs[i].SetKey(kv[0])
|
||||||
|
attrs[i].SetValue(kv[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
disableFilename, _ := cmd.Flags().GetBool("disable-filename")
|
||||||
|
if !disableFilename {
|
||||||
|
filename := filepath.Base(cmd.Flag("file").Value.String())
|
||||||
|
index := len(attrs)
|
||||||
|
attrs = append(attrs, object.Attribute{})
|
||||||
|
attrs[index].SetKey(object.AttributeFileName)
|
||||||
|
attrs[index].SetValue(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
disableTime, _ := cmd.Flags().GetBool("disable-timestamp")
|
||||||
|
if !disableTime {
|
||||||
|
index := len(attrs)
|
||||||
|
attrs = append(attrs, object.Attribute{})
|
||||||
|
attrs[index].SetKey(object.AttributeTimestamp)
|
||||||
|
attrs[index].SetValue(strconv.FormatInt(time.Now().Unix(), 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseObjectNotifications(cmd *cobra.Command) (*object.NotificationInfo, error) {
|
||||||
|
const (
|
||||||
|
separator = ":"
|
||||||
|
useDefaultTopic = "-"
|
||||||
|
)
|
||||||
|
|
||||||
|
raw := cmd.Flag(notificationFlag).Value.String()
|
||||||
|
if raw == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rawSlice := strings.SplitN(raw, separator, 2)
|
||||||
|
if len(rawSlice) != 2 {
|
||||||
|
return nil, fmt.Errorf("notification must be in the form of: *epoch*%s*topic*, got %s", separator, raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
ni := new(object.NotificationInfo)
|
||||||
|
|
||||||
|
epoch, err := strconv.ParseUint(rawSlice[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not parse notification epoch %s: %w", rawSlice[0], err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ni.SetEpoch(epoch)
|
||||||
|
|
||||||
|
if rawSlice[1] == "" {
|
||||||
|
return nil, fmt.Errorf("incorrect empty topic: use %s to force using default topic", useDefaultTopic)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rawSlice[1] != useDefaultTopic {
|
||||||
|
ni.SetTopic(rawSlice[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return ni, nil
|
||||||
|
}
|
173
cmd/neofs-cli/modules/object/range.go
Normal file
173
cmd/neofs-cli/modules/object/range.go
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
var objectRangeCmd = &cobra.Command{
|
||||||
|
Use: "range",
|
||||||
|
Short: "Get payload range data of an object",
|
||||||
|
Long: "Get payload range data of an object",
|
||||||
|
Run: getObjectRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
func initObjectRangeCmd() {
|
||||||
|
commonflags.Init(objectRangeCmd)
|
||||||
|
commonflags.InitSession(objectRangeCmd)
|
||||||
|
|
||||||
|
flags := objectRangeCmd.Flags()
|
||||||
|
|
||||||
|
flags.String("cid", "", "Container ID")
|
||||||
|
_ = objectRangeCmd.MarkFlagRequired("cid")
|
||||||
|
|
||||||
|
flags.String("oid", "", "Object ID")
|
||||||
|
_ = objectRangeCmd.MarkFlagRequired("oid")
|
||||||
|
|
||||||
|
flags.String("range", "", "Range to take data from in the form offset:length")
|
||||||
|
flags.String("file", "", "File to write object payload to. Default: stdout.")
|
||||||
|
flags.Bool(rawFlag, false, rawFlagDesc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getObjectRange(cmd *cobra.Command, _ []string) {
|
||||||
|
var cnr cid.ID
|
||||||
|
var obj oid.ID
|
||||||
|
|
||||||
|
objAddr := readObjectAddress(cmd, &cnr, &obj)
|
||||||
|
|
||||||
|
ranges, err := getRangeList(cmd)
|
||||||
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
|
if len(ranges) != 1 {
|
||||||
|
common.ExitOnErr(cmd, "", fmt.Errorf("exactly one range must be specified, got: %d", len(ranges)))
|
||||||
|
}
|
||||||
|
|
||||||
|
var out io.Writer
|
||||||
|
|
||||||
|
filename := cmd.Flag("file").Value.String()
|
||||||
|
if filename == "" {
|
||||||
|
out = os.Stdout
|
||||||
|
} else {
|
||||||
|
f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
common.ExitOnErr(cmd, "", fmt.Errorf("can't open file '%s': %w", filename, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
out = f
|
||||||
|
}
|
||||||
|
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
|
var prm internalclient.PayloadRangePrm
|
||||||
|
sessionCli.Prepare(cmd, cnr, &obj, pk, &prm)
|
||||||
|
Prepare(cmd, &prm)
|
||||||
|
|
||||||
|
raw, _ := cmd.Flags().GetBool(rawFlag)
|
||||||
|
prm.SetRawFlag(raw)
|
||||||
|
prm.SetAddress(objAddr)
|
||||||
|
prm.SetRange(ranges[0])
|
||||||
|
prm.SetPayloadWriter(out)
|
||||||
|
|
||||||
|
_, err = internalclient.PayloadRange(prm)
|
||||||
|
if err != nil {
|
||||||
|
if ok := printSplitInfoErr(cmd, err); ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
common.ExitOnErr(cmd, "can't get object payload range: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if filename != "" {
|
||||||
|
cmd.Printf("[%s] Payload successfully saved\n", filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printSplitInfoErr(cmd *cobra.Command, err error) bool {
|
||||||
|
var errSplitInfo *object.SplitInfoError
|
||||||
|
|
||||||
|
ok := errors.As(err, &errSplitInfo)
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
cmd.PrintErrln("Object is complex, split information received.")
|
||||||
|
printSplitInfo(cmd, errSplitInfo.SplitInfo())
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func printSplitInfo(cmd *cobra.Command, info *object.SplitInfo) {
|
||||||
|
bs, err := marshalSplitInfo(cmd, info)
|
||||||
|
common.ExitOnErr(cmd, "can't marshal split info: %w", err)
|
||||||
|
|
||||||
|
cmd.Println(string(bs))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalSplitInfo(cmd *cobra.Command, info *object.SplitInfo) ([]byte, error) {
|
||||||
|
toJSON, _ := cmd.Flags().GetBool("json")
|
||||||
|
toProto, _ := cmd.Flags().GetBool("proto")
|
||||||
|
switch {
|
||||||
|
case toJSON && toProto:
|
||||||
|
return nil, errors.New("'--json' and '--proto' flags are mutually exclusive")
|
||||||
|
case toJSON:
|
||||||
|
return info.MarshalJSON()
|
||||||
|
case toProto:
|
||||||
|
return info.Marshal()
|
||||||
|
default:
|
||||||
|
b := bytes.NewBuffer(nil)
|
||||||
|
if splitID := info.SplitID(); splitID != nil {
|
||||||
|
b.WriteString("Split ID: " + splitID.String() + "\n")
|
||||||
|
}
|
||||||
|
if link, ok := info.Link(); ok {
|
||||||
|
b.WriteString("Linking object: " + link.String() + "\n")
|
||||||
|
}
|
||||||
|
if last, ok := info.LastPart(); ok {
|
||||||
|
b.WriteString("Last object: " + last.String() + "\n")
|
||||||
|
}
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRangeList(cmd *cobra.Command) ([]*object.Range, error) {
|
||||||
|
v := cmd.Flag("range").Value.String()
|
||||||
|
if len(v) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
vs := strings.Split(v, ",")
|
||||||
|
rs := make([]*object.Range, len(vs))
|
||||||
|
for i := range vs {
|
||||||
|
r := strings.Split(vs[i], rangeSep)
|
||||||
|
if len(r) != 2 {
|
||||||
|
return nil, fmt.Errorf("invalid range specifier: %s", vs[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
offset, err := strconv.ParseUint(r[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid range specifier: %s", vs[i])
|
||||||
|
}
|
||||||
|
length, err := strconv.ParseUint(r[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid range specifier: %s", vs[i])
|
||||||
|
}
|
||||||
|
rs[i] = object.NewRange()
|
||||||
|
rs[i].SetOffset(offset)
|
||||||
|
rs[i].SetLength(length)
|
||||||
|
}
|
||||||
|
return rs, nil
|
||||||
|
}
|
47
cmd/neofs-cli/modules/object/root.go
Normal file
47
cmd/neofs-cli/modules/object/root.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cmd represents the object command
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "object",
|
||||||
|
Short: "Operations with Objects",
|
||||||
|
Long: `Operations with Objects`,
|
||||||
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||||
|
// bind exactly that cmd's flags to
|
||||||
|
// the viper before execution
|
||||||
|
commonflags.Bind(cmd)
|
||||||
|
commonflags.BindAPI(cmd)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
objectChildCommands := []*cobra.Command{
|
||||||
|
objectPutCmd,
|
||||||
|
objectDelCmd,
|
||||||
|
objectGetCmd,
|
||||||
|
objectSearchCmd,
|
||||||
|
objectHeadCmd,
|
||||||
|
objectHashCmd,
|
||||||
|
objectRangeCmd,
|
||||||
|
objectLockCmd}
|
||||||
|
|
||||||
|
Cmd.AddCommand(objectChildCommands...)
|
||||||
|
|
||||||
|
for _, objCommand := range objectChildCommands {
|
||||||
|
InitBearer(objCommand)
|
||||||
|
commonflags.InitAPI(objCommand)
|
||||||
|
}
|
||||||
|
|
||||||
|
initObjectPutCmd()
|
||||||
|
initObjectDeleteCmd()
|
||||||
|
initObjectGetCmd()
|
||||||
|
initObjectSearchCmd()
|
||||||
|
initObjectHeadCmd()
|
||||||
|
initObjectHashCmd()
|
||||||
|
initObjectRangeCmd()
|
||||||
|
initCommandObjectLock()
|
||||||
|
}
|
145
cmd/neofs-cli/modules/object/search.go
Normal file
145
cmd/neofs-cli/modules/object/search.go
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
|
oidSDK "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
const searchOIDFlag = "oid"
|
||||||
|
|
||||||
|
var (
|
||||||
|
searchFilters []string
|
||||||
|
|
||||||
|
objectSearchCmd = &cobra.Command{
|
||||||
|
Use: "search",
|
||||||
|
Short: "Search object",
|
||||||
|
Long: "Search object",
|
||||||
|
Run: searchObject,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func initObjectSearchCmd() {
|
||||||
|
commonflags.Init(objectSearchCmd)
|
||||||
|
commonflags.InitSession(objectSearchCmd)
|
||||||
|
|
||||||
|
flags := objectSearchCmd.Flags()
|
||||||
|
|
||||||
|
flags.String("cid", "", "Container ID")
|
||||||
|
_ = objectSearchCmd.MarkFlagRequired("cid")
|
||||||
|
|
||||||
|
flags.StringSliceVarP(&searchFilters, "filters", "f", nil,
|
||||||
|
"Repeated filter expressions or files with protobuf JSON")
|
||||||
|
|
||||||
|
flags.Bool("root", false, "Search for user objects")
|
||||||
|
flags.Bool("phy", false, "Search physically stored objects")
|
||||||
|
flags.String(searchOIDFlag, "", "Search object by identifier")
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchObject(cmd *cobra.Command, _ []string) {
|
||||||
|
var cnr cid.ID
|
||||||
|
readCID(cmd, &cnr)
|
||||||
|
|
||||||
|
sf, err := parseSearchFilters(cmd)
|
||||||
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
|
var prm internalclient.SearchObjectsPrm
|
||||||
|
sessionCli.Prepare(cmd, cnr, nil, pk, &prm)
|
||||||
|
Prepare(cmd, &prm)
|
||||||
|
prm.SetContainerID(cnr)
|
||||||
|
prm.SetFilters(sf)
|
||||||
|
|
||||||
|
res, err := internalclient.SearchObjects(prm)
|
||||||
|
common.ExitOnErr(cmd, "rpc error: %w", err)
|
||||||
|
|
||||||
|
ids := res.IDList()
|
||||||
|
|
||||||
|
cmd.Printf("Found %d objects.\n", len(ids))
|
||||||
|
for i := range ids {
|
||||||
|
cmd.Println(ids[i].String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchUnaryOpVocabulary = map[string]object.SearchMatchType{
|
||||||
|
"NOPRESENT": object.MatchNotPresent,
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchBinaryOpVocabulary = map[string]object.SearchMatchType{
|
||||||
|
"EQ": object.MatchStringEqual,
|
||||||
|
"NE": object.MatchStringNotEqual,
|
||||||
|
"COMMON_PREFIX": object.MatchCommonPrefix,
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSearchFilters(cmd *cobra.Command) (object.SearchFilters, error) {
|
||||||
|
var fs object.SearchFilters
|
||||||
|
|
||||||
|
for i := range searchFilters {
|
||||||
|
words := strings.Fields(searchFilters[i])
|
||||||
|
|
||||||
|
switch len(words) {
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid field number: %d", len(words))
|
||||||
|
case 1:
|
||||||
|
data, err := os.ReadFile(words[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not read attributes filter from file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
subFs := object.NewSearchFilters()
|
||||||
|
|
||||||
|
if err := subFs.UnmarshalJSON(data); err != nil {
|
||||||
|
return nil, fmt.Errorf("could not unmarshal attributes filter from file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = append(fs, subFs...)
|
||||||
|
case 2:
|
||||||
|
m, ok := searchUnaryOpVocabulary[words[1]]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unsupported unary op: %s", words[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.AddFilter(words[0], "", m)
|
||||||
|
case 3:
|
||||||
|
m, ok := searchBinaryOpVocabulary[words[1]]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unsupported binary op: %s", words[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.AddFilter(words[0], words[2], m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root, _ := cmd.Flags().GetBool("root")
|
||||||
|
if root {
|
||||||
|
fs.AddRootFilter()
|
||||||
|
}
|
||||||
|
|
||||||
|
phy, _ := cmd.Flags().GetBool("phy")
|
||||||
|
if phy {
|
||||||
|
fs.AddPhyFilter()
|
||||||
|
}
|
||||||
|
|
||||||
|
oid, _ := cmd.Flags().GetString(searchOIDFlag)
|
||||||
|
if oid != "" {
|
||||||
|
var id oidSDK.ID
|
||||||
|
if err := id.DecodeString(oid); err != nil {
|
||||||
|
return nil, fmt.Errorf("could not parse object ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.AddObjectIDFilter(object.MatchStringEqual, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs, nil
|
||||||
|
}
|
83
cmd/neofs-cli/modules/object/util.go
Normal file
83
cmd/neofs-cli/modules/object/util.go
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/bearer"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
bearerTokenFlag = "bearer"
|
||||||
|
|
||||||
|
rawFlag = "raw"
|
||||||
|
rawFlagDesc = "Set raw request option"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RPCParameters interface {
|
||||||
|
SetBearerToken(prm *bearer.Token)
|
||||||
|
SetTTL(uint32)
|
||||||
|
SetXHeaders([]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitBearer adds bearer token flag to a command.
|
||||||
|
func InitBearer(cmd *cobra.Command) {
|
||||||
|
flags := cmd.Flags()
|
||||||
|
flags.String(bearerTokenFlag, "", "File with signed JSON or binary encoded bearer token")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare prepares object-related parameters for a command.
|
||||||
|
func Prepare(cmd *cobra.Command, prms ...RPCParameters) {
|
||||||
|
ttl := viper.GetUint32(commonflags.TTL)
|
||||||
|
common.PrintVerbose("TTL: %d", ttl)
|
||||||
|
|
||||||
|
for i := range prms {
|
||||||
|
btok := common.ReadBearerToken(cmd, bearerTokenFlag)
|
||||||
|
|
||||||
|
prms[i].SetBearerToken(btok)
|
||||||
|
prms[i].SetTTL(ttl)
|
||||||
|
prms[i].SetXHeaders(parseXHeaders(cmd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseXHeaders(cmd *cobra.Command) []string {
|
||||||
|
xHeaders, _ := cmd.Flags().GetStringSlice(commonflags.XHeadersKey)
|
||||||
|
xs := make([]string, 0, 2*len(xHeaders))
|
||||||
|
|
||||||
|
for i := range xHeaders {
|
||||||
|
kv := strings.SplitN(xHeaders[i], "=", 2)
|
||||||
|
if len(kv) != 2 {
|
||||||
|
panic(fmt.Errorf("invalid X-Header format: %s", xHeaders[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
xs = append(xs, kv[0], kv[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return xs
|
||||||
|
}
|
||||||
|
|
||||||
|
func readObjectAddress(cmd *cobra.Command, cnr *cid.ID, obj *oid.ID) oid.Address {
|
||||||
|
readCID(cmd, cnr)
|
||||||
|
readOID(cmd, obj)
|
||||||
|
|
||||||
|
var addr oid.Address
|
||||||
|
addr.SetContainer(*cnr)
|
||||||
|
addr.SetObject(*obj)
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCID(cmd *cobra.Command, id *cid.ID) {
|
||||||
|
err := id.DecodeString(cmd.Flag("cid").Value.String())
|
||||||
|
common.ExitOnErr(cmd, "decode container ID string: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readOID(cmd *cobra.Command, id *oid.ID) {
|
||||||
|
err := id.DecodeString(cmd.Flag("oid").Value.String())
|
||||||
|
common.ExitOnErr(cmd, "decode object ID string: %w", err)
|
||||||
|
}
|
|
@ -1,10 +1,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client"
|
||||||
|
@ -16,6 +14,7 @@ import (
|
||||||
bearerCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/bearer"
|
bearerCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/bearer"
|
||||||
controlCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/control"
|
controlCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/control"
|
||||||
netmapCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/netmap"
|
netmapCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/netmap"
|
||||||
|
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
|
||||||
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
utilCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/util"
|
utilCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/util"
|
||||||
"github.com/nspcc-dev/neofs-node/misc"
|
"github.com/nspcc-dev/neofs-node/misc"
|
||||||
|
@ -80,6 +79,7 @@ func init() {
|
||||||
rootCmd.AddCommand(controlCli.Cmd)
|
rootCmd.AddCommand(controlCli.Cmd)
|
||||||
rootCmd.AddCommand(utilCli.Cmd)
|
rootCmd.AddCommand(utilCli.Cmd)
|
||||||
rootCmd.AddCommand(netmapCli.Cmd)
|
rootCmd.AddCommand(netmapCli.Cmd)
|
||||||
|
rootCmd.AddCommand(objectCli.Cmd)
|
||||||
rootCmd.AddCommand(gendoc.Command(rootCmd))
|
rootCmd.AddCommand(gendoc.Command(rootCmd))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,26 +137,3 @@ func prepareAPIClient(cmd *cobra.Command, dst ...clientWithKey) {
|
||||||
d.SetClient(cli)
|
d.SetClient(cli)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTTL() uint32 {
|
|
||||||
ttl := viper.GetUint32(commonflags.TTL)
|
|
||||||
common.PrintVerbose("TTL: %d", ttl)
|
|
||||||
|
|
||||||
return ttl
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseXHeaders(cmd *cobra.Command) []string {
|
|
||||||
xHeaders, _ := cmd.Flags().GetStringSlice(commonflags.XHeadersKey)
|
|
||||||
xs := make([]string, 0, 2*len(xHeaders))
|
|
||||||
|
|
||||||
for i := range xHeaders {
|
|
||||||
kv := strings.SplitN(xHeaders[i], "=", 2)
|
|
||||||
if len(kv) != 2 {
|
|
||||||
panic(fmt.Errorf("invalid X-Header format: %s", xHeaders[i]))
|
|
||||||
}
|
|
||||||
|
|
||||||
xs = append(xs, kv[0], kv[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return xs
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
|
||||||
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
|
||||||
|
objectCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/object"
|
||||||
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
sessionCli "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/modules/session"
|
||||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/storagegroup"
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/storagegroup"
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
@ -64,6 +65,7 @@ var sgDelCmd = &cobra.Command{
|
||||||
const (
|
const (
|
||||||
sgMembersFlag = "members"
|
sgMembersFlag = "members"
|
||||||
sgIDFlag = "id"
|
sgIDFlag = "id"
|
||||||
|
sgRawFlag = "raw"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -93,6 +95,8 @@ func initSGGetCmd() {
|
||||||
|
|
||||||
flags.StringVarP(&sgID, sgIDFlag, "", "", "storage group identifier")
|
flags.StringVarP(&sgID, sgIDFlag, "", "", "storage group identifier")
|
||||||
_ = sgGetCmd.MarkFlagRequired(sgIDFlag)
|
_ = sgGetCmd.MarkFlagRequired(sgIDFlag)
|
||||||
|
|
||||||
|
flags.Bool(sgRawFlag, false, "Set raw request option")
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSGListCmd() {
|
func initSGListCmd() {
|
||||||
|
@ -126,9 +130,7 @@ func init() {
|
||||||
storagegroupCmd.AddCommand(storageGroupChildCommands...)
|
storagegroupCmd.AddCommand(storageGroupChildCommands...)
|
||||||
|
|
||||||
for _, sgCommand := range storageGroupChildCommands {
|
for _, sgCommand := range storageGroupChildCommands {
|
||||||
flags := sgCommand.Flags()
|
objectCli.InitBearer(sgCommand)
|
||||||
|
|
||||||
flags.String(bearerTokenFlag, "", "File with signed JSON or binary encoded bearer token")
|
|
||||||
commonflags.InitAPI(sgCommand)
|
commonflags.InitAPI(sgCommand)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,12 +170,12 @@ func (c sgHeadReceiver) Head(addr oid.Address) (interface{}, error) {
|
||||||
func putSG(cmd *cobra.Command, _ []string) {
|
func putSG(cmd *cobra.Command, _ []string) {
|
||||||
pk := key.GetOrGenerate(cmd)
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
ownerID, err := getOwnerID(pk)
|
var ownerID user.ID
|
||||||
common.ExitOnErr(cmd, "", err)
|
user.IDFromKey(&ownerID, pk.PublicKey)
|
||||||
|
|
||||||
var cnr cid.ID
|
var cnr cid.ID
|
||||||
|
|
||||||
err = readCID(cmd, &cnr)
|
err := readCID(cmd, &cnr)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
members := make([]oid.ID, len(sgMembers))
|
members := make([]oid.ID, len(sgMembers))
|
||||||
|
@ -189,14 +191,14 @@ func putSG(cmd *cobra.Command, _ []string) {
|
||||||
)
|
)
|
||||||
|
|
||||||
sessionCli.Prepare(cmd, cnr, nil, pk, &putPrm)
|
sessionCli.Prepare(cmd, cnr, nil, pk, &putPrm)
|
||||||
prepareObjectPrm(cmd, &headPrm, &putPrm)
|
objectCli.Prepare(cmd, &headPrm, &putPrm)
|
||||||
|
|
||||||
headPrm.SetRawFlag(true)
|
headPrm.SetRawFlag(true)
|
||||||
|
|
||||||
sg, err := storagegroup.CollectMembers(sgHeadReceiver{
|
sg, err := storagegroup.CollectMembers(sgHeadReceiver{
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
key: pk,
|
key: pk,
|
||||||
ownerID: *ownerID,
|
ownerID: ownerID,
|
||||||
prm: headPrm,
|
prm: headPrm,
|
||||||
}, cnr, members)
|
}, cnr, members)
|
||||||
common.ExitOnErr(cmd, "could not collect storage group members: %w", err)
|
common.ExitOnErr(cmd, "could not collect storage group members: %w", err)
|
||||||
|
@ -206,7 +208,7 @@ func putSG(cmd *cobra.Command, _ []string) {
|
||||||
|
|
||||||
obj := object.New()
|
obj := object.New()
|
||||||
obj.SetContainerID(cnr)
|
obj.SetContainerID(cnr)
|
||||||
obj.SetOwnerID(ownerID)
|
obj.SetOwnerID(&ownerID)
|
||||||
obj.SetType(object.TypeStorageGroup)
|
obj.SetType(object.TypeStorageGroup)
|
||||||
|
|
||||||
putPrm.SetHeader(obj)
|
putPrm.SetHeader(obj)
|
||||||
|
@ -244,10 +246,14 @@ func getSG(cmd *cobra.Command, _ []string) {
|
||||||
|
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
var prm internalclient.GetObjectPrm
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
prepareSessionPrm(cmd, cnr, id, &prm)
|
var prm internalclient.GetObjectPrm
|
||||||
prepareObjectPrmRaw(cmd, &prm)
|
sessionCli.Prepare(cmd, cnr, id, pk, &prm)
|
||||||
|
objectCli.Prepare(cmd, &prm)
|
||||||
|
|
||||||
|
raw, _ := cmd.Flags().GetBool(sgRawFlag)
|
||||||
|
prm.SetRawFlag(raw)
|
||||||
prm.SetAddress(addr)
|
prm.SetAddress(addr)
|
||||||
prm.SetPayloadWriter(buf)
|
prm.SetPayloadWriter(buf)
|
||||||
|
|
||||||
|
@ -261,7 +267,7 @@ func getSG(cmd *cobra.Command, _ []string) {
|
||||||
|
|
||||||
cmd.Printf("Expiration epoch: %d\n", sg.ExpirationEpoch())
|
cmd.Printf("Expiration epoch: %d\n", sg.ExpirationEpoch())
|
||||||
cmd.Printf("Group size: %d\n", sg.ValidationDataSize())
|
cmd.Printf("Group size: %d\n", sg.ValidationDataSize())
|
||||||
printChecksum(cmd, "Group hash", sg.ValidationDataHash)
|
common.PrintChecksum(cmd, "Group hash", sg.ValidationDataHash)
|
||||||
|
|
||||||
if members := sg.Members(); len(members) > 0 {
|
if members := sg.Members(); len(members) > 0 {
|
||||||
cmd.Println("Members:")
|
cmd.Println("Members:")
|
||||||
|
@ -278,10 +284,11 @@ func listSG(cmd *cobra.Command, _ []string) {
|
||||||
err := readCID(cmd, &cnr)
|
err := readCID(cmd, &cnr)
|
||||||
common.ExitOnErr(cmd, "", err)
|
common.ExitOnErr(cmd, "", err)
|
||||||
|
|
||||||
var prm internalclient.SearchObjectsPrm
|
pk := key.GetOrGenerate(cmd)
|
||||||
|
|
||||||
prepareSessionPrm(cmd, cnr, nil, &prm)
|
var prm internalclient.SearchObjectsPrm
|
||||||
prepareObjectPrm(cmd, &prm)
|
sessionCli.Prepare(cmd, cnr, nil, pk, &prm)
|
||||||
|
objectCli.Prepare(cmd, &prm)
|
||||||
prm.SetContainerID(cnr)
|
prm.SetContainerID(cnr)
|
||||||
prm.SetFilters(storagegroup.SearchQuery())
|
prm.SetFilters(storagegroup.SearchQuery())
|
||||||
|
|
||||||
|
@ -312,8 +319,9 @@ func delSG(cmd *cobra.Command, _ []string) {
|
||||||
|
|
||||||
var prm internalclient.DeleteObjectPrm
|
var prm internalclient.DeleteObjectPrm
|
||||||
|
|
||||||
prepareSessionPrm(cmd, cnr, id, &prm)
|
pk := key.GetOrGenerate(cmd)
|
||||||
prepareObjectPrm(cmd, &prm)
|
sessionCli.Prepare(cmd, cnr, id, pk, &prm)
|
||||||
|
objectCli.Prepare(cmd, &prm)
|
||||||
prm.SetAddress(addr)
|
prm.SetAddress(addr)
|
||||||
|
|
||||||
res, err := internalclient.DeleteObject(prm)
|
res, err := internalclient.DeleteObject(prm)
|
||||||
|
@ -324,3 +332,12 @@ func delSG(cmd *cobra.Command, _ []string) {
|
||||||
cmd.Println("Storage group removed successfully.")
|
cmd.Println("Storage group removed successfully.")
|
||||||
cmd.Printf(" Tombstone: %s\n", tomb)
|
cmd.Printf(" Tombstone: %s\n", tomb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readCID(cmd *cobra.Command, cnr *cid.ID) error {
|
||||||
|
err := cnr.DecodeString(cmd.Flag("cid").Value.String())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("decode container ID string: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue