150 lines
4.3 KiB
Go
150 lines
4.3 KiB
Go
package metabase
|
|
|
|
import (
|
|
"context"
|
|
"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"
|
|
morphconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/morph"
|
|
nodeconfig "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config/node"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
|
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
|
morphcontainer "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
const (
|
|
noCompactFlag = "no-compact"
|
|
)
|
|
|
|
var (
|
|
errNoPathsFound = errors.New("no metabase paths found")
|
|
errNoMorphEndpointsFound = errors.New("no morph endpoints found")
|
|
)
|
|
|
|
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
|
|
}
|
|
appCfg := config.New(configFile, configDir, config.EnvPrefix)
|
|
paths, err := getMetabasePaths(appCfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(paths) == 0 {
|
|
return errNoPathsFound
|
|
}
|
|
cmd.Println("found", len(paths), "metabases:")
|
|
for i, path := range paths {
|
|
cmd.Println(i+1, ":", path)
|
|
}
|
|
mc, err := createMorphClient(cmd.Context(), appCfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer mc.Close()
|
|
civ, err := createContainerInfoProvider(mc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
noCompact, _ := cmd.Flags().GetBool(noCompactFlag)
|
|
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, civ, 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 getMetabasePaths(appCfg *config.Config) ([]string, error) {
|
|
var paths []string
|
|
if err := engineconfig.IterateShards(appCfg, false, func(sc *shardconfig.Config) error {
|
|
paths = append(paths, sc.Metabase().Path())
|
|
return nil
|
|
}); err != nil {
|
|
return nil, fmt.Errorf("get metabase paths: %w", err)
|
|
}
|
|
return paths, nil
|
|
}
|
|
|
|
func createMorphClient(ctx context.Context, appCfg *config.Config) (*client.Client, error) {
|
|
addresses := morphconfig.RPCEndpoint(appCfg)
|
|
if len(addresses) == 0 {
|
|
return nil, errNoMorphEndpointsFound
|
|
}
|
|
key := nodeconfig.Key(appCfg)
|
|
cli, err := client.New(ctx,
|
|
key,
|
|
client.WithDialTimeout(morphconfig.DialTimeout(appCfg)),
|
|
client.WithEndpoints(addresses...),
|
|
client.WithSwitchInterval(morphconfig.SwitchInterval(appCfg)),
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create morph client:%w", err)
|
|
}
|
|
return cli, nil
|
|
}
|
|
|
|
func createContainerInfoProvider(cli *client.Client) (container.InfoProvider, error) {
|
|
sh, err := cli.NNSContractAddress(client.NNSContainerContractName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("resolve container contract hash: %w", err)
|
|
}
|
|
cc, err := morphcontainer.NewFromMorph(cli, sh, 0, morphcontainer.TryNotary())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create morph container client: %w", err)
|
|
}
|
|
return container.NewInfoProvider(func() (container.Source, error) {
|
|
return morphcontainer.AsContainerSource(cc), nil
|
|
}), nil
|
|
}
|
|
|
|
func initUpgradeCommand() {
|
|
flags := UpgradeCmd.Flags()
|
|
flags.Bool(noCompactFlag, false, "Do not compact upgraded metabase file")
|
|
}
|