From 4ded500a4507e9b052230e23401ffc7d944e90ed Mon Sep 17 00:00:00 2001 From: Andrey Butusov Date: Tue, 15 Oct 2024 12:53:21 +0300 Subject: [PATCH] neofs-cli/control: add `object revive` control command Support command that revive object by purging all removal marks from all metabases. ``` $ neofs-cli control object status --endpoint s04.neofs.devenv:8081 -w services/storage/wallet04.json --object 4yYJV2AyHaJ3fpVimEihAj6NTkwmanbwE7YatJUWBPyM/CYUeRyjfiNXhBMW9XZmdSBJNVLXYBH3gSNQASWTGZX8t Enter password > Shard ID: 2wEzFvWsao9yBiDWKjSBfF metabase: AVAILABLE peapod: path: "/storage/peapod1.db" $ neofs-cli object delete -r s04.neofs.devenv:8080 -w services/storage/wallet04 .json --cid 4yYJV2AyHaJ3fpVimEihAj6NTkwmanbwE7YatJUWBPyM --oid CYUeRyjfiNXhBMW9XZmdSBJNVLXYBH3gSNQASWTGZX8t Enter password > Object CYUeRyjfiNXhBMW9XZmdSBJNVLXYBH3gSNQASWTGZX8t removed successfully. ID: C2LrMExCF3FTfQaFYYZfoDGLpsUVLUy156pUpWh72YeN CID: 4yYJV2AyHaJ3fpVimEihAj6NTkwmanbwE7YatJUWBPyM $ neofs-cli control object status --endpoint s04.neofs.devenv:8081 -w services/storage/wallet04.json --object 4yYJV2AyHaJ3fpVimEihAj6NTkwmanbwE7YatJUWBPyM/CYUeRyjfiNXhBMW9XZmdSBJNVLXYBH3gSNQASWTGZX8t Enter password > Shard ID: 2wEzFvWsao9yBiDWKjSBfF metabase: AVAILABLE,IN GRAVEYARD peapod: path: "/storage/peapod1.db" $ neofs-cli control object revive --endpoint s04.neofs.devenv:8081 -w services/storage/wallet04.json --object 4yYJV2AyHaJ3fpVimEihAj6NTkwmanbwE7YatJUWBPyM/CYUeRyjfiNXhBMW9XZmdSBJNVLXYBH3gSNQASWTGZX8t Enter password > Shard ID: Vuy2Q8QaPZSuUxDycPxSBC Revival status: don't revive, err: logical error: object neither in the graveyard nor was marked with GC mark Shard ID: 2wEzFvWsao9yBiDWKjSBfF Revival status: successful revival from graveyard, tomb: 4yYJV2AyHaJ3fpVimEihAj6NTkwmanbwE7YatJUWBPyM/C2LrMExCF3FTfQaFYYZfoDGLpsUVLUy156pUpWh72YeN $ neofs-cli control object status --endpoint s04.neofs.devenv:8081 -w services/storage/wallet04.json --object 4yYJV2AyHaJ3fpVimEihAj6NTkwmanbwE7YatJUWBPyM/CYUeRyjfiNXhBMW9XZmdSBJNVLXYBH3gSNQASWTGZX8t Enter password > Shard ID: 2wEzFvWsao9yBiDWKjSBfF metabase: AVAILABLE peapod: path: "/storage/peapod1.db" ``` Closes #1450. Signed-off-by: Andrey Butusov --- CHANGELOG.md | 1 + cmd/neofs-cli/modules/control/object.go | 4 + .../modules/control/object_revive.go | 89 +++++++++++++++++++ .../modules/control/object_status.go | 2 - 4 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 cmd/neofs-cli/modules/control/object_revive.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 071cca2620..c1cab338cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ attribute, which is used for container domain name in NNS contracts (#2954) - Save last epoch when metabase was resynchronized (#2966) - `neofs-lens meta last-resync-epoch` command (#2966) - `neofs-lens fstree cleanup-tmp` command (#2967) +- `neofs-cli control object revive` command (#2968) ### Fixed - Do not search for tombstones when handling their expiration, use local indexes instead (#2929) diff --git a/cmd/neofs-cli/modules/control/object.go b/cmd/neofs-cli/modules/control/object.go index 831a477a7f..dcb05dc934 100644 --- a/cmd/neofs-cli/modules/control/object.go +++ b/cmd/neofs-cli/modules/control/object.go @@ -4,6 +4,8 @@ import ( "github.com/spf13/cobra" ) +const objectFlag = "object" + var objectCmd = &cobra.Command{ Use: "object", Short: "Direct object operations with storage engine", @@ -12,7 +14,9 @@ var objectCmd = &cobra.Command{ func initControlObjectsCmd() { objectCmd.AddCommand(listObjectsCmd) objectCmd.AddCommand(objectStatusCmd) + objectCmd.AddCommand(reviveObjectCmd) + initControlObjectReviveCmd() initControlObjectsListCmd() initObjectStatusFlags() } diff --git a/cmd/neofs-cli/modules/control/object_revive.go b/cmd/neofs-cli/modules/control/object_revive.go new file mode 100644 index 0000000000..9fb2c6394e --- /dev/null +++ b/cmd/neofs-cli/modules/control/object_revive.go @@ -0,0 +1,89 @@ +package control + +import ( + "fmt" + + rawclient "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" + "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/pkg/services/control" + oid "github.com/nspcc-dev/neofs-sdk-go/object/id" + "github.com/spf13/cobra" +) + +var reviveObjectCmd = &cobra.Command{ + Use: "revive", + Short: "Forcefully revive object", + Long: "Purge removal marks from metabases", + Args: cobra.NoArgs, + RunE: reviveObject, +} + +func initControlObjectReviveCmd() { + initControlFlags(reviveObjectCmd) + + flags := reviveObjectCmd.Flags() + flags.String(objectFlag, "", "Object address") +} + +func reviveObject(cmd *cobra.Command, _ []string) error { + ctx, cancel := commonflags.GetCommandContext(cmd) + defer cancel() + + pk, err := key.Get(cmd) + if err != nil { + return err + } + addressRaw, err := cmd.Flags().GetString(objectFlag) + if err != nil { + return fmt.Errorf("reading %s flag: %w", objectFlag, err) + } + + var sdkAddr oid.Address + err = sdkAddr.DecodeString(addressRaw) + if err != nil { + return fmt.Errorf("validating address (%s): %w", addressRaw, err) + } + + var resp *control.ReviveObjectResponse + req := &control.ReviveObjectRequest{ + Body: &control.ReviveObjectRequest_Body{ + ObjectAddress: addressRaw, + }, + } + err = signRequest(pk, req) + if err != nil { + return err + } + + cli, err := getClient(ctx) + if err != nil { + return err + } + + err = cli.ExecRaw(func(client *rawclient.Client) error { + resp, err = control.ReviveObject(client, req) + return err + }) + if err != nil { + return fmt.Errorf("rpc error: %w", err) + } + + err = verifyResponse(resp.GetSignature(), resp.GetBody()) + if err != nil { + return err + } + + shards := resp.GetBody().GetShards() + if len(shards) == 0 { + cmd.Println("") + return nil + } + + for _, shard := range shards { + cmd.Printf("Shard ID: %s\n", shard.ShardId) + cmd.Printf("Revival status: %s\n", shard.Status) + } + + return nil +} diff --git a/cmd/neofs-cli/modules/control/object_status.go b/cmd/neofs-cli/modules/control/object_status.go index 5eed21e866..6d976c9d94 100644 --- a/cmd/neofs-cli/modules/control/object_status.go +++ b/cmd/neofs-cli/modules/control/object_status.go @@ -11,8 +11,6 @@ import ( "github.com/spf13/cobra" ) -const objectFlag = "object" - var objectStatusCmd = &cobra.Command{ Use: "status", Short: "Check current object status",