[#9999] adm: Add dry-run flag to zombie scan command
Some checks failed
DCO action / DCO (pull_request) Successful in 45s
Vulncheck / Vulncheck (pull_request) Failing after 1m14s
Build / Build Components (pull_request) Successful in 1m21s
Tests and linters / Staticcheck (pull_request) Successful in 2m50s
Tests and linters / Lint (pull_request) Successful in 2m55s
Tests and linters / Tests (pull_request) Successful in 3m0s
Tests and linters / Tests with -race (pull_request) Successful in 3m25s
Tests and linters / gopls check (pull_request) Successful in 3m56s

This allows to just print object addresses that should be moved to quarantine.

Change-Id: I551979d8bffaf45fe21d92f6edadfaadcb5d6e25
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
Dmitrii Stepanov 2025-03-31 12:25:57 +03:00
parent 6278986d62
commit 87c9e53c29
Signed by: dstepanov-yadro
GPG key ID: 237AF1A763293BC0
2 changed files with 39 additions and 23 deletions

View file

@ -18,6 +18,8 @@ const (
walletFlagUsage = "Path to the wallet or binary key"
addressFlag = "address"
addressFlagUsage = "Address of wallet account"
dryRunFlag = "dry-run"
dryRunFlagUsage = "Print addresses of objects - candidates for quarantine without actually moving"
)
var (
@ -36,6 +38,7 @@ var (
_ = viper.BindPFlag(walletFlag, cmd.Flags().Lookup(walletFlag))
_ = viper.BindPFlag(addressFlag, cmd.Flags().Lookup(addressFlag))
_ = viper.BindPFlag(flagBatchSize, cmd.Flags().Lookup(flagBatchSize))
_ = viper.BindPFlag(dryRunFlag, cmd.Flags().Lookup(dryRunFlag))
},
Run: scan,
}
@ -92,6 +95,7 @@ func initScanCmd() {
scanCmd.Flags().Uint32(flagBatchSize, 1000, flagBatchSizeUsage)
scanCmd.Flags().StringP(walletFlag, walletFlagShorthand, "", walletFlagUsage)
scanCmd.Flags().String(addressFlag, "", addressFlagUsage)
scanCmd.Flags().Bool(dryRunFlag, false, dryRunFlagUsage)
}
func initListCmd() {

View file

@ -34,6 +34,7 @@ func scan(cmd *cobra.Command, _ []string) {
if batchSize == 0 {
commonCmd.ExitOnErr(cmd, "invalid batch size: %w", errors.New("batch size must be positive value"))
}
dryRun, _ := cmd.Flags().GetBool(dryRunFlag)
storageEngine := newEngine(cmd, appCfg)
morphClient := createMorphClient(cmd, appCfg)
@ -76,7 +77,7 @@ func scan(cmd *cobra.Command, _ []string) {
}()
go func() {
defer wg.Done()
err = scanStorageEngine(cmd.Context(), batchSize, storageEngine, ps, appCfg, cnrCli, nmCli, q, pk)
err = scanStorageEngine(cmd, batchSize, storageEngine, ps, appCfg, cnrCli, nmCli, q, pk, dryRun)
close(stopCh)
}()
wg.Wait()
@ -156,8 +157,8 @@ func checkAddr(ctx context.Context, cnrCli *cntClient.Client, nmCli *netmap.Clie
return statusQuarantine, nil
}
func scanStorageEngine(ctx context.Context, batchSize uint32, storageEngine *engine.StorageEngine, ps *processStatus,
appCfg *config.Config, cnrCli *cntClient.Client, nmCli *netmap.Client, q *quarantine, pk *ecdsa.PrivateKey,
func scanStorageEngine(cmd *cobra.Command, batchSize uint32, storageEngine *engine.StorageEngine, ps *processStatus,
appCfg *config.Config, cnrCli *cntClient.Client, nmCli *netmap.Client, q *quarantine, pk *ecdsa.PrivateKey, dryRun bool,
) error {
cc := cache.NewSDKClientCache(cache.ClientCacheOpts{
DialTimeout: apiclientconfig.DialTimeout(appCfg),
@ -166,6 +167,7 @@ func scanStorageEngine(ctx context.Context, batchSize uint32, storageEngine *eng
Key: pk,
AllowExternal: apiclientconfig.AllowExternal(appCfg),
})
ctx := cmd.Context()
var cursor *engine.Cursor
for {
@ -197,30 +199,17 @@ func scanStorageEngine(ctx context.Context, batchSize uint32, storageEngine *eng
eg.Go(func() error {
result, err := checkAddr(egCtx, cnrCli, nmCli, cc, addr.Address)
if err != nil {
return fmt.Errorf("check object %s status: %w", addr, err)
return fmt.Errorf("check object %s status: %w", addr.Address, err)
}
ps.add(result)
if dryRun && result == statusQuarantine {
cmd.Println(addr)
return nil
}
if result == statusQuarantine {
var getPrm engine.GetPrm
getPrm.WithAddress(addr.Address)
res, err := storageEngine.Get(egCtx, getPrm)
if err != nil {
return fmt.Errorf("get object %s from storage engine: %w", addr, err)
}
if err := q.Put(egCtx, res.Object()); err != nil {
return fmt.Errorf("put object %s to quarantine: %w", addr, err)
}
var delPrm engine.DeletePrm
delPrm.WithForceRemoval()
delPrm.WithAddress(addr.Address)
_, err = storageEngine.Delete(egCtx, delPrm)
if err != nil {
return fmt.Errorf("delete object %s from storage engine: %w", addr, err)
}
return moveToQuarantine(egCtx, storageEngine, q, addr.Address)
}
return nil
})
@ -231,6 +220,29 @@ func scanStorageEngine(ctx context.Context, batchSize uint32, storageEngine *eng
}
}
func moveToQuarantine(ctx context.Context, storageEngine *engine.StorageEngine, q *quarantine, addr oid.Address) error {
var getPrm engine.GetPrm
getPrm.WithAddress(addr)
res, err := storageEngine.Get(ctx, getPrm)
if err != nil {
return fmt.Errorf("get object %s from storage engine: %w", addr, err)
}
if err := q.Put(ctx, res.Object()); err != nil {
return fmt.Errorf("put object %s to quarantine: %w", addr, err)
}
var delPrm engine.DeletePrm
delPrm.WithForceRemoval()
delPrm.WithAddress(addr)
_, err = storageEngine.Delete(ctx, delPrm)
if err != nil {
return fmt.Errorf("delete object %s from storage engine: %w", addr, err)
}
return nil
}
type processStatus struct {
guard sync.RWMutex
statusCount map[status]uint64