forked from TrueCloudLab/frostfs-node
212 lines
5.6 KiB
Go
212 lines
5.6 KiB
Go
package object
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
|
internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/key"
|
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-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)
|
|
initFlagSession(objectHeadCmd, "HEAD")
|
|
|
|
flags := objectHeadCmd.Flags()
|
|
|
|
flags.String(commonflags.CIDFlag, "", commonflags.CIDFlagUsage)
|
|
_ = objectHeadCmd.MarkFlagRequired(commonflags.CIDFlag)
|
|
|
|
flags.String(commonflags.OIDFlag, "", commonflags.OIDFlagUsage)
|
|
_ = objectHeadCmd.MarkFlagRequired(commonflags.OIDFlag)
|
|
|
|
flags.String(fileFlag, "", "File to write header to. Default: stdout.")
|
|
flags.Bool(commonflags.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)
|
|
pk := key.GetOrGenerate(cmd)
|
|
|
|
cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC)
|
|
|
|
var prm internalclient.HeadObjectPrm
|
|
prm.SetClient(cli)
|
|
Prepare(cmd, &prm)
|
|
readSession(cmd, &prm, pk, cnr, obj)
|
|
|
|
raw, _ := cmd.Flags().GetBool(rawFlag)
|
|
prm.SetRawFlag(raw)
|
|
prm.SetAddress(objAddr)
|
|
|
|
res, err := internalclient.HeadObject(cmd.Context(), prm)
|
|
if err != nil {
|
|
if ok := printSplitInfoErr(cmd, err); ok {
|
|
return
|
|
}
|
|
|
|
if ok := printECInfoErr(cmd, err); ok {
|
|
return
|
|
}
|
|
|
|
commonCmd.ExitOnErr(cmd, "rpc error: %w", err)
|
|
}
|
|
|
|
err = saveAndPrintHeader(cmd, res.Header(), cmd.Flag(fileFlag).Value.String())
|
|
commonCmd.ExitOnErr(cmd, "", err)
|
|
}
|
|
|
|
func saveAndPrintHeader(cmd *cobra.Command, obj *objectSDK.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 *objectSDK.Object) ([]byte, error) {
|
|
toJSON, _ := cmd.Flags().GetBool(commonflags.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() (oid.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 *objectSDK.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() == objectSDK.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())
|
|
}
|
|
|
|
if signature := obj.Signature(); signature != nil {
|
|
cmd.Print("ID signature:\n")
|
|
|
|
// TODO(@carpawell): #468 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()))
|
|
}
|
|
|
|
if ecHeader := obj.ECHeader(); ecHeader != nil {
|
|
cmd.Print("EC header:\n")
|
|
|
|
cmd.Printf(" parent object ID: %s\n", ecHeader.Parent().EncodeToString())
|
|
cmd.Printf(" index: %d\n", ecHeader.Index())
|
|
cmd.Printf(" total: %d\n", ecHeader.Total())
|
|
cmd.Printf(" header length: %d\n", ecHeader.HeaderLength())
|
|
}
|
|
|
|
return printSplitHeader(cmd, obj)
|
|
}
|
|
|
|
func printSplitHeader(cmd *cobra.Command, obj *objectSDK.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())
|
|
}
|
|
|
|
parent := obj.Parent()
|
|
if parent != nil {
|
|
cmd.Print("\nSplit Parent Header:\n")
|
|
|
|
return printHeader(cmd, parent)
|
|
}
|
|
|
|
return nil
|
|
}
|