package metabase import ( "errors" "fmt" "sync" "time" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config" engineconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/engine" shardconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/engine/shard" meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" ) const ( pathFlag = "path" noCompactFlag = "no-compact" ) var errNoPathsFound = errors.New("no metabase paths found") var path string var UpgradeCmd = &cobra.Command{ Use: "upgrade", Short: "Upgrade metabase to latest version", RunE: upgrade, } func upgrade(cmd *cobra.Command, _ []string) error { configFile, err := cmd.Flags().GetString(commonflags.ConfigFlag) if err != nil { return err } configDir, err := cmd.Flags().GetString(commonflags.ConfigDirFlag) if err != nil { return err } noCompact, _ := cmd.Flags().GetBool(noCompactFlag) var paths []string if path != "" { paths = append(paths, path) } appCfg := config.New(configFile, configDir, config.EnvPrefix) if err := engineconfig.IterateShards(appCfg, false, func(sc *shardconfig.Config) error { paths = append(paths, sc.Metabase().Path()) return nil }); err != nil { return fmt.Errorf("failed to get metabase paths: %w", err) } if len(paths) == 0 { return errNoPathsFound } cmd.Println("found", len(paths), "metabases:") for i, path := range paths { cmd.Println(i+1, ":", path) } result := make(map[string]bool) var resultGuard sync.Mutex eg, ctx := errgroup.WithContext(cmd.Context()) for _, path := range paths { eg.Go(func() error { var success bool cmd.Println("upgrading metabase", path, "...") if err := meta.Upgrade(ctx, path, !noCompact, func(a ...any) { cmd.Println(append([]any{time.Now().Format(time.RFC3339), ":", path, ":"}, a...)...) }); err != nil { cmd.Println("error: failed to upgrade metabase", path, ":", err) } else { success = true cmd.Println("metabase", path, "upgraded successfully") } resultGuard.Lock() result[path] = success resultGuard.Unlock() return nil }) } if err := eg.Wait(); err != nil { return err } for mb, ok := range result { if ok { cmd.Println(mb, ": success") } else { cmd.Println(mb, ": failed") } } return nil } func initUpgradeCommand() { flags := UpgradeCmd.Flags() flags.StringVar(&path, pathFlag, "", "Path to metabase file") flags.Bool(noCompactFlag, false, "Do not compact upgraded metabase file") }