-
-
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
config: command to apply profile after init #4195
Changes from 9 commits
20d6803
b59354b
d7376cd
ed88179
75b235d
9312fa5
c573d3d
2514c74
0ff9b24
acb4edc
ac26cf1
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 |
---|---|---|
|
@@ -142,6 +142,7 @@ Set the value of the 'Datastore.Path' key: | |
"show": configShowCmd, | ||
"edit": configEditCmd, | ||
"replace": configReplaceCmd, | ||
"profile": configProfileCmd, | ||
}, | ||
} | ||
|
||
|
@@ -293,6 +294,92 @@ can't be undone. | |
}, | ||
} | ||
|
||
var configProfileCmd = &cmds.Command{ | ||
Helptext: cmdkit.HelpText{ | ||
Tagline: "Apply profiles to config.", | ||
}, | ||
|
||
Subcommands: map[string]*cmds.Command{ | ||
"apply": configProfileApplyCmd, | ||
"revert": configProfileRevertCmd, | ||
}, | ||
} | ||
|
||
var configProfileApplyCmd = &cmds.Command{ | ||
Helptext: cmdkit.HelpText{ | ||
Tagline: "Apply profile to config.", | ||
}, | ||
Arguments: []cmdkit.Argument{ | ||
cmdkit.StringArg("profile", true, false, "The profile to apply to the config."), | ||
}, | ||
Run: func(req cmds.Request, res cmds.Response) { | ||
profile, ok := config.Profiles[req.Arguments()[0]] | ||
if !ok { | ||
res.SetError(fmt.Errorf("%s is not a profile", req.Arguments()[0]), cmdkit.ErrNormal) | ||
return | ||
} | ||
|
||
err := transformConfig(req.InvocContext().ConfigRoot, profile.Apply) | ||
if err != nil { | ||
res.SetError(err, cmdkit.ErrNormal) | ||
return | ||
} | ||
res.SetOutput(nil) | ||
}, | ||
} | ||
|
||
var configProfileRevertCmd = &cmds.Command{ | ||
Helptext: cmdkit.HelpText{ | ||
Tagline: "Revert profile changes.", | ||
ShortDescription: `Reverts profile-related changes to the default values. | ||
|
||
Reverting some profiles may damage the configuration or not be possible. | ||
Backing up the config before running this command is advised.`, | ||
}, | ||
Arguments: []cmdkit.Argument{ | ||
cmdkit.StringArg("profile", true, false, "The profile to apply to the config."), | ||
}, | ||
Run: func(req cmds.Request, res cmds.Response) { | ||
profile, ok := config.Profiles[req.Arguments()[0]] | ||
if !ok { | ||
res.SetError(fmt.Errorf("%s is not a profile", req.Arguments()[0]), cmdkit.ErrNormal) | ||
return | ||
} | ||
|
||
err := transformConfig(req.InvocContext().ConfigRoot, profile.Revert) | ||
if err != nil { | ||
res.SetError(err, cmdkit.ErrNormal) | ||
return | ||
} | ||
res.SetOutput(nil) | ||
}, | ||
} | ||
|
||
func transformConfig(configRoot string, transformer config.Transformer) error { | ||
r, err := fsrepo.Open(configRoot) | ||
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. if the daemon is running while the user runs this they might run into issues. You cant open the repo again 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. probably best to pass in the repo from the IpfsNode 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. That's what other commands here do. Looking at repo.Open it should be safe: func Open(repoPath string) (repo.Repo, error) {
fn := func() (repo.Repo, error) {
return open(repoPath)
}
return onlyOne.Open(repoPath, fn)
} 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. oh, i see. good point. |
||
if err != nil { | ||
return err | ||
} | ||
defer r.Close() | ||
|
||
cfg, err := r.Config() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = transformer(cfg) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = r.BackupConfig("profile-") | ||
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. After making
To provide more helpful backup names. |
||
if err != nil { | ||
return err | ||
} | ||
|
||
return r.SetConfig(cfg) | ||
} | ||
|
||
func getConfig(r repo.Repo, key string) (*ConfigField, error) { | ||
value, err := r.GetConfigKey(key) | ||
if err != nil { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,33 @@ The go-ipfs config file is a json document. It is read once at node instantiatio | |
either for an offline command, or when starting the daemon. Commands that execute | ||
on a running daemon do not read the config file at runtime. | ||
|
||
#### Profiles | ||
Configuration profiles allow to tweak configuration quickly. Profiles can be | ||
applied with `--profile` flag to `ipfs init` or with `ipfs config profile apply` | ||
command. | ||
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. I would mention that a backup is created and what it is called. |
||
|
||
Available profiles: | ||
- `server` | ||
|
||
Recommended for nodes with public IPv4 address, disables host and content | ||
discovery in local networks. | ||
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. Or those running on VPSs. |
||
|
||
- `test` | ||
|
||
Reduces external interference, useful for running ipfs in test environments. | ||
Note that with these settings node won't be able to talk to the rest of the | ||
network without manual bootstrap. | ||
|
||
- `badgerds` | ||
|
||
Replaces default datastore configuration with experimental badger datastore. | ||
If you apply this profile after `ipfs init`, you will need to convert your | ||
datastore to the new configuration. You can do this using [ipfs-ds-convert](https://github.com/ipfs/ipfs-ds-convert) | ||
|
||
WARNING: badger datastore is experimantal. Make sure to backup your data | ||
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. badger datastore is experimental |
||
frequently | ||
|
||
|
||
## Table of Contents | ||
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. @whyrusleeping should we document the 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. Its somewhat out of scope, but probably a good idea. 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. Out of scope? I meant to add under the new Profiles section in case that wasn't clear. 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. @kevina ah, gotcha. Yeah, lets get that in here. |
||
|
||
- [`Addresses`](#addresses) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,89 @@ | ||
package config | ||
|
||
// ConfigProfiles is a map holding configuration transformers | ||
var ConfigProfiles = map[string]func(*Config) error{ | ||
"server": func(c *Config) error { | ||
|
||
// defaultServerFilters has a list of non-routable IPv4 prefixes | ||
// according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml | ||
defaultServerFilters := []string{ | ||
"/ip4/10.0.0.0/ipcidr/8", | ||
"/ip4/100.64.0.0/ipcidr/10", | ||
"/ip4/169.254.0.0/ipcidr/16", | ||
"/ip4/172.16.0.0/ipcidr/12", | ||
"/ip4/192.0.0.0/ipcidr/24", | ||
"/ip4/192.0.0.0/ipcidr/29", | ||
"/ip4/192.0.0.8/ipcidr/32", | ||
"/ip4/192.0.0.170/ipcidr/32", | ||
"/ip4/192.0.0.171/ipcidr/32", | ||
"/ip4/192.0.2.0/ipcidr/24", | ||
"/ip4/192.168.0.0/ipcidr/16", | ||
"/ip4/198.18.0.0/ipcidr/15", | ||
"/ip4/198.51.100.0/ipcidr/24", | ||
"/ip4/203.0.113.0/ipcidr/24", | ||
"/ip4/240.0.0.0/ipcidr/4", | ||
} | ||
|
||
c.Swarm.AddrFilters = append(c.Swarm.AddrFilters, defaultServerFilters...) | ||
c.Discovery.MDNS.Enabled = false | ||
return nil | ||
// Transformer is a function which takes configuration and applies some filter to it | ||
type Transformer func(c *Config) error | ||
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. I would make this a struct something like
|
||
|
||
// Profile applies some set of changes to the configuration | ||
type Profile struct { | ||
Apply Transformer | ||
Revert Transformer | ||
} | ||
|
||
// Profiles is a map holding configuration transformers. Docs are in docs/config.md | ||
var Profiles = map[string]*Profile{ | ||
"server": { | ||
Apply: func(c *Config) error { | ||
|
||
// defaultServerFilters has a list of non-routable IPv4 prefixes | ||
// according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml | ||
defaultServerFilters := []string{ | ||
"/ip4/10.0.0.0/ipcidr/8", | ||
"/ip4/100.64.0.0/ipcidr/10", | ||
"/ip4/169.254.0.0/ipcidr/16", | ||
"/ip4/172.16.0.0/ipcidr/12", | ||
"/ip4/192.0.0.0/ipcidr/24", | ||
"/ip4/192.0.0.0/ipcidr/29", | ||
"/ip4/192.0.0.8/ipcidr/32", | ||
"/ip4/192.0.0.170/ipcidr/32", | ||
"/ip4/192.0.0.171/ipcidr/32", | ||
"/ip4/192.0.2.0/ipcidr/24", | ||
"/ip4/192.168.0.0/ipcidr/16", | ||
"/ip4/198.18.0.0/ipcidr/15", | ||
"/ip4/198.51.100.0/ipcidr/24", | ||
"/ip4/203.0.113.0/ipcidr/24", | ||
"/ip4/240.0.0.0/ipcidr/4", | ||
} | ||
|
||
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. Not really related to this PR, but i was just thinking that we should probably add LAN addresses to the 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. Done |
||
c.Addresses.NoAnnounce = append(c.Addresses.NoAnnounce, defaultServerFilters...) | ||
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. We should probably try merging these instead of just appending. |
||
c.Swarm.AddrFilters = append(c.Swarm.AddrFilters, defaultServerFilters...) | ||
c.Discovery.MDNS.Enabled = false | ||
return nil | ||
}, | ||
Revert: func(c *Config) error { | ||
c.Addresses.NoAnnounce = []string{} | ||
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. If we do keep the revert command, we should only remove the ones we've added. |
||
c.Swarm.AddrFilters = []string{} | ||
c.Discovery.MDNS.Enabled = true | ||
return nil | ||
}, | ||
}, | ||
"test": func(c *Config) error { | ||
c.Addresses.API = "/ip4/127.0.0.1/tcp/0" | ||
c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" | ||
|
||
c.Swarm.DisableNatPortMap = true | ||
c.Addresses.Swarm = []string{ | ||
"/ip4/127.0.0.1/tcp/0", | ||
} | ||
|
||
c.Bootstrap = []string{} | ||
c.Discovery.MDNS.Enabled = false | ||
return nil | ||
"test": { | ||
Apply: func(c *Config) error { | ||
c.Addresses.API = "/ip4/127.0.0.1/tcp/0" | ||
c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" | ||
c.Addresses.Swarm = []string{ | ||
"/ip4/127.0.0.1/tcp/0", | ||
} | ||
|
||
c.Swarm.DisableNatPortMap = true | ||
|
||
c.Bootstrap = []string{} | ||
c.Discovery.MDNS.Enabled = false | ||
return nil | ||
}, | ||
Revert: func(c *Config) error { | ||
c.Addresses = addressesConfig() | ||
|
||
c.Swarm.DisableNatPortMap = false | ||
c.Discovery.MDNS.Enabled = true | ||
return nil | ||
}, | ||
}, | ||
"badgerds": func(c *Config) error { | ||
c.Datastore.Spec = map[string]interface{}{ | ||
"type": "measure", | ||
"prefix": "badger.datastore", | ||
"child": map[string]interface{}{ | ||
"type": "badgerds", | ||
"path": "badgerds", | ||
"syncWrites": true, | ||
}, | ||
} | ||
return nil | ||
"badgerds": { | ||
Apply: func(c *Config) error { | ||
c.Datastore.Spec = map[string]interface{}{ | ||
"type": "measure", | ||
"prefix": "badger.datastore", | ||
"child": map[string]interface{}{ | ||
"type": "badgerds", | ||
"path": "badgerds", | ||
"syncWrites": true, | ||
}, | ||
} | ||
return nil | ||
}, | ||
Revert: func(c *Config) error { | ||
c.Datastore.Spec = DefaultDatastoreConfig().Spec | ||
return nil | ||
}, | ||
}, | ||
} |
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.
Actually reverting is impossible (for us). We're not reverting, we're applying the inverse of the profile. Do we really need to provide this feature?
We could, instead, provide inverse profiles: local-discovery and flatfs-ds.
I'm worried that a user will think that profiles act like drop-ins (that's how a lot of unix daemons work) and will believe that revert will revert the apply.
Alternatively, we could just do this with layered drop-ins (but that's more complex).
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.
I agree with @Stebalien this is not really a revert so we perhaps we should name it something else, not sure what, "unapply" comes to mind.
The idea of instead providing inverse profiles is also a good idea.
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.
I think I like the idea of inverse profiles better, I'll see how that looks