diff --git a/cmd/frostfs-cli/modules/object/get.go b/cmd/frostfs-cli/modules/object/get.go index f1edccba2..7a9e10711 100644 --- a/cmd/frostfs-cli/modules/object/get.go +++ b/cmd/frostfs-cli/modules/object/get.go @@ -40,6 +40,7 @@ func initObjectGetCmd() { flags.Bool(rawFlag, false, rawFlagDesc) flags.Bool(noProgressFlag, false, "Do not show progress bar") flags.Bool(binaryFlag, false, "Serialize whole object structure into given file(id + signature + header + payload).") + flags.Bool("locate", false, "Print shard info") } func getObject(cmd *cobra.Command, _ []string) { @@ -107,6 +108,13 @@ func getObject(cmd *cobra.Command, _ []string) { } processResult(cmd, res, binary, payloadBuffer, out, filename) + + findShard, err := cmd.Flags().GetBool("locate") + commonCmd.ExitOnErr(cmd, "", err) + if findShard { + loc := GetObjectLocation(cmd) + printShardInfo(cmd, loc) + } } func processResult(cmd *cobra.Command, res *internalclient.GetObjectRes, binary bool, payloadBuffer *bytes.Buffer, out io.Writer, filename string) { diff --git a/cmd/frostfs-cli/modules/object/locate.go b/cmd/frostfs-cli/modules/object/locate.go new file mode 100644 index 000000000..521b7bebd --- /dev/null +++ b/cmd/frostfs-cli/modules/object/locate.go @@ -0,0 +1,111 @@ +package object + +import ( + "crypto/ecdsa" + "errors" + + internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/client" + "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" + "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control" + "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/server/ctrlmessage" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rawclient "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" + + "github.com/mr-tron/base58" + "github.com/spf13/cobra" +) + +func GetObjectLocation(cmd *cobra.Command) control.ShardInfo { + pk := key.Get(cmd) + + req := new(control.GetShardByObjectIDRequest) + req.SetBody(new(control.GetShardByObjectIDRequest_Body)) + + signRequest(cmd, pk, req) + + cli := internalclient.GetSDKClientByFlag(cmd, pk, commonflags.RPC) + + var resp *control.GetShardByObjectIDResponse + var err error + err = cli.ExecRaw(func(client *rawclient.Client) error { + resp, err = control.GetShardByObjectID(client, req) + return err + }) + commonCmd.ExitOnErr(cmd, "rpc error loc: %w", err) + + verifyResponse(cmd, resp.GetSignature(), resp.GetBody()) + return *resp.GetBody().GetShards() +} + +func signRequest(cmd *cobra.Command, pk *ecdsa.PrivateKey, req ctrlmessage.SignedMessage) { + err := ctrlmessage.Sign(pk, req) + commonCmd.ExitOnErr(cmd, "could not sign request: %w", err) +} + +func verifyResponse(cmd *cobra.Command, + sigControl interface { + GetKey() []byte + GetSign() []byte + }, + body interface { + MarshalProtobuf([]byte) []byte + }, +) { + if sigControl == nil { + commonCmd.ExitOnErr(cmd, "", errors.New("missing response signature")) + } + + // TODO(@cthulhu-rider): #468 use Signature message from FrostFS API to avoid conversion + var sigV2 refs.Signature + sigV2.SetScheme(refs.ECDSA_SHA512) + sigV2.SetKey(sigControl.GetKey()) + sigV2.SetSign(sigControl.GetSign()) + + var sig frostfscrypto.Signature + commonCmd.ExitOnErr(cmd, "can't read signature: %w", sig.ReadFromV2(sigV2)) + + if !sig.Verify(body.MarshalProtobuf(nil)) { + commonCmd.ExitOnErr(cmd, "", errors.New("invalid response signature")) + } +} + +func printShardInfo(cmd *cobra.Command, info control.ShardInfo) { + cmd.Printf("shard_id: %v\n", base58.Encode(info.GetShard_ID())) + cmd.Printf("mode: %s\n", shardModeToString(info.GetMode())) + cmd.Printf("metabase: %s\n", info.GetMetabasePath()) + cmd.Printf("blobstor: %v\n", info.GetBlobstor()) + cmd.Printf("writecache: %s\n", info.GetWritecachePath()) + cmd.Printf("pilorama: %s\n", info.GetPiloramaPath()) + cmd.Printf("error_count: %v\n", info.GetErrorCount()) + cmd.Printf("evacuation_in_progress: %v\n", info.GetEvacuationInProgress()) +} + +func shardModeToString(m control.ShardMode) string { + strMode, ok := lookUpShardModeString(m) + if ok { + return strMode + } + + return "unknown" +} + +// looks up for string representation of supported shard mode. Returns false +// if mode is not supported. +func lookUpShardModeString(m control.ShardMode) (string, bool) { + mShardModes := map[string]control.ShardMode{ + "read-only": control.ShardMode_READ_ONLY, + "read-write": control.ShardMode_READ_WRITE, + "degraded-read-write": control.ShardMode_DEGRADED, + "degraded-read-only": control.ShardMode_DEGRADED_READ_ONLY, + } + for strMode, mode := range mShardModes { + if mode == m { + return strMode, true + } + } + + return "", false +} diff --git a/go.mod b/go.mod index cc6b0a202..f8f4243e2 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,14 @@ go 1.22 require ( code.gitea.io/sdk/gitea v0.17.1 - git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1-0.20241205083807-762d7f9f9f08 + git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1 git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 git.frostfs.info/TrueCloudLab/frostfs-locode-db v0.4.1-0.20240710074952-65761deb5c0d git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20241112082307-f17779933e88 git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20250202151421-8389887a3421 git.frostfs.info/TrueCloudLab/hrw v1.2.1 git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972 - git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240814080254-96225afacb88 + git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240822104152-a3bc3099bd5b git.frostfs.info/TrueCloudLab/tzhash v1.8.0 git.frostfs.info/TrueCloudLab/zapjournald v0.0.0-20240124114243-cb2e66427d02 github.com/VictoriaMetrics/easyproto v0.1.4 diff --git a/go.sum b/go.sum index eae467b31..b9d745d91 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ code.gitea.io/sdk/gitea v0.17.1 h1:3jCPOG2ojbl8AcfaUCRYLT5MUcBMFwS0OSK2mA5Zok8= code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2miadoTNM= -git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1-0.20241205083807-762d7f9f9f08 h1:tl1TT+zNk1lF/J5EaD3syDrTaYbQwvJKVOVENM4oQ+k= -git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1-0.20241205083807-762d7f9f9f08/go.mod h1:5fSm/l5xSjGWqsPUffSdboiGFUHa7y/1S0fvxzQowN8= +git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1 h1:k1Qw8dWUQczfo0eVXlhrq9eXEbUMyDLW8jEMzY+gxMc= +git.frostfs.info/TrueCloudLab/frostfs-contract v0.21.1/go.mod h1:5fSm/l5xSjGWqsPUffSdboiGFUHa7y/1S0fvxzQowN8= git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk= git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU= git.frostfs.info/TrueCloudLab/frostfs-locode-db v0.4.1-0.20240710074952-65761deb5c0d h1:uJ/wvuMdepbkaV8XMS5uN9B0FQWMep0CttSuDZiDhq0= @@ -16,8 +16,8 @@ git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972 h1:/96 git.frostfs.info/TrueCloudLab/multinet v0.0.0-20241015075604-6cb0d80e0972/go.mod h1:2hM42MBrlhvN6XToaW6OWNk5ZLcu1FhaukGgxtfpDDI= git.frostfs.info/TrueCloudLab/neoneo-go v0.106.1-0.20241015133823-8aee80dbdc07 h1:gPaqGsk6gSWQyNVjaStydfUz6Z/loHc9XyvGrJ5qSPY= git.frostfs.info/TrueCloudLab/neoneo-go v0.106.1-0.20241015133823-8aee80dbdc07/go.mod h1:bZyJexBlrja4ngxiBgo8by5pVHuAbhg9l09/8yVGDyg= -git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240814080254-96225afacb88 h1:vgbfkcnIexZUm3vREBBSa/Gv1Whjd1SFCUd0A+IaGPQ= -git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240814080254-96225afacb88/go.mod h1:SgioiGhQNWqiV5qpFAXRDJF81SEFRBhtwGEiU0FViyA= +git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240822104152-a3bc3099bd5b h1:M50kdfrf/h8c3cz0bJ2AEUcbXvAlPFVC1Wp1WkfZ/8E= +git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20240822104152-a3bc3099bd5b/go.mod h1:GZTk55RI4dKzsK6BCn5h2xxE28UHNfgoq/NJxW/LQ6A= git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9mwVfJ+SjT3HA= git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0/go.mod h1:okpbKfVYf/BpejtfFTfhZqFP+sZ8rsHrP8Rr/jYPNRc= git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjqZzS4gsb4UA=