Add 'ipfs repo migrate' command (#8428)
* Add 'ipfs repo migrate' command This PR replaces #7658 that was originally contributed by zaibons, in order to move code into a branch and avoid some CI problem. The command allows the user to run the repo migration without starting the daemon. resolves #7471 * return non-ErrNeedMigration errors from fsrepo.Open() Co-authored-by: Gus Eggert <gus@gus.dev>
Andrew Gillis committed
May 6, 2022 at 14:34 UTC
889f73e90e55cc17c7c434d1a21c9e091deed626
4 files changed
+111
-6
core/commands/commands_test.go
+1
@@ -217,6 +217,7 @@ func TestCommands(t *testing.T) {
217
"/repo",
218
"/repo/fsck",
219
"/repo/gc",
220
+ "/repo/migrate",
221
"/repo/stat",
222
"/repo/verify",
223
"/repo/version",
core/commands/repo.go
+72
-4
@@ -11,11 +11,14 @@ import (
11
"sync"
12
"text/tabwriter"
13
14
- humanize "github.com/dustin/go-humanize"
14
+ oldcmds "github.com/ipfs/go-ipfs/commands"
15
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
16
corerepo "github.com/ipfs/go-ipfs/core/corerepo"
17
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
18
+ "github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
19
+ "github.com/ipfs/go-ipfs/repo/fsrepo/migrations/ipfsfetcher"
20
21
+ humanize "github.com/dustin/go-humanize"
22
cid "github.com/ipfs/go-cid"
23
bstore "github.com/ipfs/go-ipfs-blockstore"
24
cmds "github.com/ipfs/go-ipfs-cmds"
@@ -39,6 +42,7 @@ var RepoCmd = &cmds.Command{
42
"fsck": repoFsckCmd,
43
"version": repoVersionCmd,
44
"verify": repoVerifyCmd,
45
+ "migrate": repoMigrateCmd,
46
},
47
}
48
@@ -49,9 +53,10 @@ type GcResult struct {
53
}
54
55
const (
52
- repoStreamErrorsOptionName = "stream-errors"
53
- repoQuietOptionName = "quiet"
54
- repoSilentOptionName = "silent"
56
+ repoStreamErrorsOptionName = "stream-errors"
57
+ repoQuietOptionName = "quiet"
58
+ repoSilentOptionName = "silent"
59
+ repoAllowDowngradeOptionName = "allow-downgrade"
60
)
61
62
var repoGcCmd = &cmds.Command{
@@ -387,3 +392,66 @@ var repoVersionCmd = &cmds.Command{
392
}),
393
},
394
}
395
+
396
+var repoMigrateCmd = &cmds.Command{
397
+ Helptext: cmds.HelpText{
398
+ Tagline: "Apply any outstanding migrations to the repo.",
399
+ },
400
+ Options: []cmds.Option{
401
+ cmds.BoolOption(repoAllowDowngradeOptionName, "Allow downgrading to a lower repo version"),
402
+ },
403
+ NoRemote: true,
404
+ Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
405
+ cctx := env.(*oldcmds.Context)
406
+ allowDowngrade, _ := req.Options[repoAllowDowngradeOptionName].(bool)
407
+
408
+ _, err := fsrepo.Open(cctx.ConfigRoot)
409
+
410
+ if err == nil {
411
+ fmt.Println("Repo does not require migration.")
412
+ return nil
413
+ } else if err != fsrepo.ErrNeedMigration {
414
+ return err
415
+ }
416
+
417
+ fmt.Println("Found outdated fs-repo, starting migration.")
418
+
419
+ // Read Migration section of IPFS config
420
+ configFileOpt, _ := req.Options[ConfigFileOption].(string)
421
+ migrationCfg, err := migrations.ReadMigrationConfig(cctx.ConfigRoot, configFileOpt)
422
+ if err != nil {
423
+ return err
424
+ }
425
+
426
+ // Define function to create IPFS fetcher. Do not supply an
427
+ // already-constructed IPFS fetcher, because this may be expensive and
428
+ // not needed according to migration config. Instead, supply a function
429
+ // to construct the particular IPFS fetcher implementation used here,
430
+ // which is called only if an IPFS fetcher is needed.
431
+ newIpfsFetcher := func(distPath string) migrations.Fetcher {
432
+ return ipfsfetcher.NewIpfsFetcher(distPath, 0, &cctx.ConfigRoot, configFileOpt)
433
+ }
434
+
435
+ // Fetch migrations from current distribution, or location from environ
436
+ fetchDistPath := migrations.GetDistPathEnv(migrations.CurrentIpfsDist)
437
+
438
+ // Create fetchers according to migrationCfg.DownloadSources
439
+ fetcher, err := migrations.GetMigrationFetcher(migrationCfg.DownloadSources, fetchDistPath, newIpfsFetcher)
440
+ if err != nil {
441
+ return err
442
+ }
443
+ defer fetcher.Close()
444
+
445
+ err = migrations.RunMigration(cctx.Context(), fetcher, fsrepo.RepoVersion, "", allowDowngrade)
446
+ if err != nil {
447
+ fmt.Println("The migrations of fs-repo failed:")
448
+ fmt.Printf(" %s\n", err)
449
+ fmt.Println("If you think this is a bug, please file an issue and include this whole log output.")
450
+ fmt.Println(" https://github.com/ipfs/fs-repo-migrations")
451
+ return err
452
+ }
453
+
454
+ fmt.Printf("Success: fs-repo has been migrated to version %d.\n", fsrepo.RepoVersion)
455
+ return nil
456
+ },
457
+}
repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go
-2
@@ -247,8 +247,6 @@ func (f *IpfsFetcher) startTempNode(ctx context.Context) error {
247
cancel()
248
// Wait until ipfs is stopped
249
<-node.Context().Done()
250
-
251
- fmt.Println("migration peer", node.Identity, "shutdown")
250
}
251
252
addrs, err := ipfs.Swarm().LocalAddrs(ctx)
test/sharness/t0066-migration.sh
+38
@@ -84,4 +84,42 @@ test_expect_success "output looks good" '
84
grep "Please get fs-repo-migrations from https://dist.ipfs.io" daemon_out > /dev/null
85
'
86
87
+test_expect_success "ipfs repo migrate succeed" '
88
+ test_expect_code 0 ipfs repo migrate > migrate_out
89
+'
90
+
91
+test_expect_success "output looks good" '
92
+ grep "Found outdated fs-repo, starting migration." migrate_out > /dev/null &&
93
+ grep "Success: fs-repo migrated to version $IPFS_REPO_VER" true_out > /dev/null
94
+'
95
+
96
+test_expect_success "manually reset repo version to latest" '
97
+ echo "$IPFS_REPO_VER" > "$IPFS_PATH"/version
98
+'
99
+
100
+test_expect_success "detect repo does not need migration" '
101
+ test_expect_code 0 ipfs repo migrate > migrate_out
102
+'
103
+
104
+test_expect_success "output looks good" '
105
+ grep "Repo does not require migration" migrate_out > /dev/null
106
+'
107
+
108
+# ensure that we get a lock error if we need to migrate and the daemon is running
109
+test_launch_ipfs_daemon
110
+
111
+test_expect_success "manually reset repo version to $MIGRATION_START" '
112
+ echo "$MIGRATION_START" > "$IPFS_PATH"/version
113
+'
114
+
115
+test_expect_success "ipfs repo migrate fails" '
116
+ test_expect_code 1 ipfs repo migrate 2> migrate_out
117
+'
118
+
119
+test_expect_success "output looks good" '
120
+ grep "repo.lock" migrate_out > /dev/null
121
+'
122
+
123
+test_kill_ipfs_daemon
124
+
125
test_done