-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(cmds): files: add new-root command to change the MFS root #8648
base: master
Are you sure you want to change the base?
Changes from 3 commits
247816a
cb1212f
a0f16cc
7e0f38e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,10 +13,14 @@ import ( | |
humanize "github.com/dustin/go-humanize" | ||
"github.com/ipfs/go-ipfs/core" | ||
"github.com/ipfs/go-ipfs/core/commands/cmdenv" | ||
"github.com/ipfs/go-ipfs/core/node" | ||
"github.com/ipfs/go-ipfs/repo/fsrepo" | ||
|
||
bservice "github.com/ipfs/go-blockservice" | ||
cid "github.com/ipfs/go-cid" | ||
cidenc "github.com/ipfs/go-cidutil/cidenc" | ||
"github.com/ipfs/go-datastore" | ||
fslock "github.com/ipfs/go-fs-lock" | ||
cmds "github.com/ipfs/go-ipfs-cmds" | ||
offline "github.com/ipfs/go-ipfs-exchange-offline" | ||
ipld "github.com/ipfs/go-ipld-format" | ||
|
@@ -70,16 +74,17 @@ operations. | |
cmds.BoolOption(filesFlushOptionName, "f", "Flush target and ancestors after write.").WithDefault(true), | ||
}, | ||
Subcommands: map[string]*cmds.Command{ | ||
"read": filesReadCmd, | ||
"write": filesWriteCmd, | ||
"mv": filesMvCmd, | ||
"cp": filesCpCmd, | ||
"ls": filesLsCmd, | ||
"mkdir": filesMkdirCmd, | ||
"stat": filesStatCmd, | ||
"rm": filesRmCmd, | ||
"flush": filesFlushCmd, | ||
"chcid": filesChcidCmd, | ||
"read": filesReadCmd, | ||
"write": filesWriteCmd, | ||
"mv": filesMvCmd, | ||
"cp": filesCpCmd, | ||
"ls": filesLsCmd, | ||
"mkdir": filesMkdirCmd, | ||
"stat": filesStatCmd, | ||
"rm": filesRmCmd, | ||
"flush": filesFlushCmd, | ||
"chcid": filesChcidCmd, | ||
"replace-root": filesReplaceRoot, | ||
}, | ||
} | ||
|
||
|
@@ -1134,6 +1139,111 @@ Remove files or directories. | |
}, | ||
} | ||
|
||
var filesReplaceRoot = &cmds.Command{ | ||
Helptext: cmds.HelpText{ | ||
Tagline: "Replace the filesystem root.", | ||
ShortDescription: ` | ||
Replace the filesystem root with another CID when the filesystem has been corrupted. | ||
`, | ||
LongDescription: ` | ||
Replace the filesystem root with another CID. | ||
This command is meant to run in standalone mode when the daemon isn't running. | ||
It is an advanced command that you normally do *not* want to run except when | ||
the filesystem has been corrupted and the daemon refuses to run. | ||
|
||
FIXME: Add an example of the daemon not running once https://github.com/ipfs/go-ipfs/issues/7183 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO |
||
is resolved. | ||
|
||
$ ipfs init | ||
[...] | ||
ipfs cat /ipfs/QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc/readme # <- init dir | ||
[...] | ||
$ ipfs files ls / | ||
[nothing; empty dir] | ||
$ ipfs files stat / --hash | ||
QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn | ||
# FIXME(BLOCKING): Need the following to somehow "start" the root dir, otherwise | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO |
||
# the replace-root will fail to find the '/local/filesroot' entry in the repo | ||
$ ipfs files cp /ipfs/QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc/readme /file | ||
$ GOLOG_LOG_LEVEL="info" ipfs files replace-root QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc # init dir from before | ||
[...] replaced MFS files root QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc [...] | ||
[here we have the CID of the old root to "undo" in case of error] | ||
$ ipfs files ls / | ||
[contents from init dir now set as the root of the filesystem] | ||
about | ||
contact | ||
help | ||
ping | ||
quick-start | ||
readme | ||
security-notes | ||
$ ipfs files replace-root QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn # empty dir from init | ||
$ ipfs files ls / | ||
[nothing; empty dir] | ||
`, | ||
}, | ||
Arguments: []cmds.Argument{ | ||
cmds.StringArg("new-root", true, false, "New root to use."), | ||
}, | ||
// FIXME(BLOCKING): Can/should we do this with the repo running? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO |
||
NoRemote: true, | ||
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { | ||
if len(req.Arguments) < 1 { | ||
return fmt.Errorf("new root not provided") | ||
} | ||
newFilesRootCid, err := cid.Parse(req.Arguments[0]) | ||
if err != nil { | ||
return fmt.Errorf("files root argument provided %s is not a valid CID: %w", req.Arguments[0], err) | ||
|
||
} | ||
// FIXME(BLOCKING): Check (a) that this CID exists *locally* and (b) | ||
// that it's a dir. | ||
Comment on lines
+1254
to
+1255
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO |
||
|
||
cfgRoot, err := cmdenv.GetConfigRoot(env) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
repo, err := fsrepo.Open(cfgRoot) | ||
if err != nil { | ||
if pathError, ok := err.(*os.PathError); ok { | ||
if _, isLockError := pathError.Unwrap().(fslock.LockedError); isLockError { | ||
return fmt.Errorf("aquiring the repo lock (make sure the daemon isn't running): %w", err) | ||
} | ||
} | ||
return err | ||
} | ||
localDS := repo.Datastore() | ||
defer repo.Close() | ||
|
||
filesRootBytes, err := localDS.Get(req.Context, node.FilesRootDatastoreKey) | ||
if err == datastore.ErrNotFound { | ||
return fmt.Errorf("MFS files root %s not found in repo", node.FilesRootDatastoreKey) | ||
} else if err != nil { | ||
return fmt.Errorf("looking for MFS files root: %w", err) | ||
} | ||
filesRootCid, err := cid.Cast(filesRootBytes) | ||
if err != nil { | ||
return fmt.Errorf("casting MFS files root %s as CID: %w", filesRootBytes, err) | ||
} | ||
|
||
err = localDS.Put(req.Context, node.FilesRootDatastoreKey, newFilesRootCid.Bytes()) | ||
if err != nil { | ||
return fmt.Errorf("storing new files root: %w", err) | ||
} | ||
// FIXME(BLOCKING): Do we need this if we're closing the repo at the end | ||
// of the command? Likely not. | ||
Comment on lines
+1289
to
+1290
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO |
||
err = localDS.Sync(req.Context, node.FilesRootDatastoreKey) | ||
if err != nil { | ||
return fmt.Errorf("syncing new files root: %w", err) | ||
} | ||
|
||
log.Infof("replaced MFS files root %s with %s", filesRootCid, newFilesRootCid) | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
func getPrefixNew(req *cmds.Request) (cid.Builder, error) { | ||
cidVer, cidVerSet := req.Options[filesCidVersionOptionName].(int) | ||
hashFunStr, hashFunSet := req.Options[filesHashOptionName].(string) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💭 loose thoughts
mkdir
mv
cp
rm
, perhaps this one should be namedchroot
?chcid
, which would allow in-place swapping of CIDs for any path (not just root)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current name came from an informal Slack thread, but I'm fine with whatever is decided. My 2 cents on
chroot
is that it might imply some temporary change related to the running daemon/process when in fact we're doing a long-term modification of the single filesystem available (since we don't have any jail/sandbox abstractions).This sounds like it is beyond the scope of this issue which is fixing a corrupted filesystem preventing daemon startup (corruption in sub-paths wouldn't have the same effect). The idea is valid on itself though, maybe we should discuss it in another issue as a feature request.