mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-10-31 02:28:31 -04:00
feat: make space2share migration repeatable
This commit is contained in:
1 file changed
+96
@@ -3,6 +3,9 @@ package command
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
@@ -16,6 +19,7 @@ import (
|
||||
sharingparser "github.com/opencloud-eu/opencloud/services/sharing/pkg/config/parser"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/share/manager/jsoncs3"
|
||||
migration "github.com/opencloud-eu/reva/v2/pkg/share/manager/jsoncs3/migrations"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/share/manager/registry"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
|
||||
@@ -31,6 +35,10 @@ import (
|
||||
// this executions is not returned this timeout is needed
|
||||
const cleanupTimeout = 1 * time.Minute
|
||||
|
||||
// migrationTimeout bounds a forced migration run. Importing the grants of many
|
||||
// project spaces is not fast, so this is generous.
|
||||
const migrationTimeout = 30 * time.Minute
|
||||
|
||||
// SharesCommand is the entrypoint for the groups command.
|
||||
func SharesCommand(cfg *config.Config) *cobra.Command {
|
||||
sharesCmd := &cobra.Command{
|
||||
@@ -48,6 +56,7 @@ func SharesCommand(cfg *config.Config) *cobra.Command {
|
||||
},
|
||||
}
|
||||
sharesCmd.AddCommand(cleanupCmd(cfg))
|
||||
sharesCmd.AddCommand(migrateCmd(cfg))
|
||||
|
||||
return sharesCmd
|
||||
}
|
||||
@@ -139,6 +148,93 @@ func cleanup(_ *cobra.Command, cfg *config.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const migrationWaitTimeout = 30 * time.Minute
|
||||
|
||||
func migrateCmd(cfg *config.Config) *cobra.Command {
|
||||
migrateCmd := &cobra.Command{
|
||||
Use: "migrate [migration]",
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if list, _ := cmd.Flags().GetBool("list"); list {
|
||||
return nil
|
||||
}
|
||||
if len(args) != 1 {
|
||||
return fmt.Errorf("name the migration to run, one of: %s", strings.Join(migration.Names(), ", "))
|
||||
}
|
||||
// reject an unknown name before touching the configuration
|
||||
if !slices.Contains(migration.Names(), args[0]) {
|
||||
return fmt.Errorf("unknown migration %q, one of: %s", args[0], strings.Join(migration.Names(), ", "))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Short: `re-run share manager migrations that have already been applied.`,
|
||||
Long: `Runs a share manager migration by name, whether or not it has been applied
|
||||
before. On startup a migration runs only once; this runs the one you name.
|
||||
|
||||
The case this exists for is import_space_members: it reads the grants of every
|
||||
project space from the storage provider and imports them into the share
|
||||
manager. Space memberships that were written as storage grants by something
|
||||
other than OpenCloud are invisible until that has run. The import is additive,
|
||||
so running it again is safe.
|
||||
|
||||
Use --list to see the available migrations.`,
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
// listing the migrations needs no server configuration
|
||||
if list, _ := cmd.Flags().GetBool("list"); list {
|
||||
return nil
|
||||
}
|
||||
if err := parser.ParseConfig(cfg, true); err != nil {
|
||||
return configlog.ReturnError(err)
|
||||
}
|
||||
|
||||
cfg.Sharing.Commons = cfg.Commons
|
||||
return configlog.ReturnError(sharingparser.ParseConfig(cfg.Sharing))
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return migrate(cmd, cfg, args)
|
||||
},
|
||||
}
|
||||
|
||||
migrateCmd.Flags().BoolP("list", "l", false, "list the available migrations and exit")
|
||||
_ = viper.BindPFlag("list", migrateCmd.Flags().Lookup("list"))
|
||||
|
||||
return migrateCmd
|
||||
}
|
||||
|
||||
func migrate(_ *cobra.Command, cfg *config.Config, args []string) error {
|
||||
if viper.GetBool("list") {
|
||||
for _, name := range migration.Names() {
|
||||
fmt.Println(name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
driver := cfg.Sharing.UserSharingDriver
|
||||
if driver != "jsoncs3" {
|
||||
return configlog.ReturnError(errors.New("migrate is only implemented for the jsoncs3 share manager"))
|
||||
}
|
||||
|
||||
l := logger("migrate")
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
|
||||
// Initialize registry to make service lookup work
|
||||
_ = mregistry.GetRegistry()
|
||||
|
||||
rcfg := revaShareConfig(cfg.Sharing)
|
||||
f, ok := registry.NewFuncs[driver]
|
||||
if !ok {
|
||||
return configlog.ReturnError(errors.New("Unknown share manager type '" + driver + "'"))
|
||||
}
|
||||
mgr, err := f(rcfg[driver].(map[string]any), &l)
|
||||
if err != nil {
|
||||
return configlog.ReturnError(err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(l.WithContext(context.Background()), migrationTimeout)
|
||||
defer cancel()
|
||||
|
||||
return configlog.ReturnError(mgr.(*jsoncs3.Manager).RunMigration(ctx, args[0]))
|
||||
}
|
||||
|
||||
func revaShareConfig(cfg *sharing.Config) map[string]any {
|
||||
return map[string]any{
|
||||
"json": map[string]any{
|
||||
|
||||
Reference in new issue
Block a user