Merge pull request #1966 from laser/feat/reload-config

expose config-setting through Repo interface
This commit is contained in:
Łukasz Magiera 2020-06-11 18:15:06 +02:00 committed by GitHub
commit 1c583ab487
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 103 additions and 10 deletions

View File

@ -12,7 +12,7 @@ import (
) )
// FromFile loads config from a specified file overriding defaults specified in // FromFile loads config from a specified file overriding defaults specified in
// the def parameter. If file does not exist or is empty defaults are asummed. // the def parameter. If file does not exist or is empty defaults are assumed.
func FromFile(path string, def interface{}) (interface{}, error) { func FromFile(path string, def interface{}) (interface{}, error) {
file, err := os.Open(path) file, err := os.Open(path)
switch { switch {

View File

@ -11,6 +11,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/BurntSushi/toml"
"github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore"
fslock "github.com/ipfs/go-fs-lock" fslock "github.com/ipfs/go-fs-lock"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
@ -229,6 +230,7 @@ type fsLockedRepo struct {
dsOnce sync.Once dsOnce sync.Once
storageLk sync.Mutex storageLk sync.Mutex
configLk sync.Mutex
} }
func (fsr *fsLockedRepo) Path() string { func (fsr *fsLockedRepo) Path() string {
@ -265,12 +267,50 @@ func (fsr *fsLockedRepo) stillValid() error {
} }
func (fsr *fsLockedRepo) Config() (interface{}, error) { func (fsr *fsLockedRepo) Config() (interface{}, error) {
if err := fsr.stillValid(); err != nil { fsr.configLk.Lock()
return nil, err defer fsr.configLk.Unlock()
}
return fsr.loadConfigFromDisk()
}
func (fsr *fsLockedRepo) loadConfigFromDisk() (interface{}, error) {
return config.FromFile(fsr.join(fsConfig), defConfForType(fsr.repoType)) return config.FromFile(fsr.join(fsConfig), defConfForType(fsr.repoType))
} }
func (fsr *fsLockedRepo) SetConfig(c func(interface{})) error {
if err := fsr.stillValid(); err != nil {
return err
}
fsr.configLk.Lock()
defer fsr.configLk.Unlock()
cfg, err := fsr.loadConfigFromDisk()
if err != nil {
return err
}
// mutate in-memory representation of config
c(cfg)
// buffer into which we write TOML bytes
buf := new(bytes.Buffer)
// encode now-mutated config as TOML and write to buffer
err = toml.NewEncoder(buf).Encode(cfg)
if err != nil {
return err
}
// write buffer of TOML bytes to config file
err = ioutil.WriteFile(fsr.join(fsConfig), buf.Bytes(), 0644)
if err != nil {
return err
}
return nil
}
func (fsr *fsLockedRepo) GetStorage() (stores.StorageConfig, error) { func (fsr *fsLockedRepo) GetStorage() (stores.StorageConfig, error) {
fsr.storageLk.Lock() fsr.storageLk.Lock()
defer fsr.storageLk.Unlock() defer fsr.storageLk.Unlock()

View File

@ -38,6 +38,7 @@ type LockedRepo interface {
// Returns config in this repo // Returns config in this repo
Config() (interface{}, error) Config() (interface{}, error)
SetConfig(func(interface{})) error
GetStorage() (stores.StorageConfig, error) GetStorage() (stores.StorageConfig, error)
SetStorage(func(*stores.StorageConfig)) error SetStorage(func(*stores.StorageConfig)) error

View File

@ -30,8 +30,16 @@ type MemRepo struct {
token *byte token *byte
datastore datastore.Datastore datastore datastore.Datastore
configF func(t RepoType) interface{}
keystore map[string]types.KeyInfo keystore map[string]types.KeyInfo
// given a repo type, produce the default config
configF func(t RepoType) interface{}
// holds the current config value
config struct {
sync.Mutex
val interface{}
}
} }
type lockedMemRepo struct { type lockedMemRepo struct {
@ -45,6 +53,10 @@ type lockedMemRepo struct {
} }
func (lmem *lockedMemRepo) GetStorage() (stores.StorageConfig, error) { func (lmem *lockedMemRepo) GetStorage() (stores.StorageConfig, error) {
if err := lmem.checkToken(); err != nil {
return stores.StorageConfig{}, err
}
if lmem.sc == nil { if lmem.sc == nil {
lmem.sc = &stores.StorageConfig{StoragePaths: []stores.LocalPath{ lmem.sc = &stores.StorageConfig{StoragePaths: []stores.LocalPath{
{Path: lmem.Path()}, {Path: lmem.Path()},
@ -55,6 +67,10 @@ func (lmem *lockedMemRepo) GetStorage() (stores.StorageConfig, error) {
} }
func (lmem *lockedMemRepo) SetStorage(c func(*stores.StorageConfig)) error { func (lmem *lockedMemRepo) SetStorage(c func(*stores.StorageConfig)) error {
if err := lmem.checkToken(); err != nil {
return err
}
_, _ = lmem.GetStorage() _, _ = lmem.GetStorage()
c(lmem.sc) c(lmem.sc)
@ -221,11 +237,32 @@ func (lmem *lockedMemRepo) Config() (interface{}, error) {
if err := lmem.checkToken(); err != nil { if err := lmem.checkToken(); err != nil {
return nil, err return nil, err
} }
return lmem.mem.configF(lmem.t), nil
lmem.mem.config.Lock()
defer lmem.mem.config.Unlock()
if lmem.mem.config.val == nil {
lmem.mem.config.val = lmem.mem.configF(lmem.t)
}
return lmem.mem.config.val, nil
} }
func (lmem *lockedMemRepo) Storage() (stores.StorageConfig, error) { func (lmem *lockedMemRepo) SetConfig(c func(interface{})) error {
panic("implement me") if err := lmem.checkToken(); err != nil {
return err
}
lmem.mem.config.Lock()
defer lmem.mem.config.Unlock()
if lmem.mem.config.val == nil {
lmem.mem.config.val = lmem.mem.configF(lmem.t)
}
c(lmem.mem.config.val)
return nil
} }
func (lmem *lockedMemRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error { func (lmem *lockedMemRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error {

View File

@ -9,6 +9,8 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/config"
"github.com/stretchr/testify/require"
) )
func basicTest(t *testing.T, repo Repo) { func basicTest(t *testing.T, repo Repo) {
@ -47,10 +49,23 @@ func basicTest(t *testing.T, repo Repo) {
assert.NoError(t, err, "setting multiaddr shouldn't error") assert.NoError(t, err, "setting multiaddr shouldn't error")
assert.Equal(t, ma, apima, "returned API multiaddr should be the same") assert.Equal(t, ma, apima, "returned API multiaddr should be the same")
cfg, err := lrepo.Config() c1, err := lrepo.Config()
assert.Equal(t, config.DefaultFullNode(), cfg, "there should be a default config") assert.Equal(t, config.DefaultFullNode(), c1, "there should be a default config")
assert.NoError(t, err, "config should not error") assert.NoError(t, err, "config should not error")
// mutate config and persist back to repo
err = lrepo.SetConfig(func(c interface{}) {
cfg := c.(*config.FullNode)
cfg.Client.IpfsMAddr = "duvall"
})
assert.NoError(t, err)
// load config and verify changes
c2, err := lrepo.Config()
require.NoError(t, err)
cfg2 := c2.(*config.FullNode)
require.Equal(t, cfg2.Client.IpfsMAddr, "duvall")
err = lrepo.Close() err = lrepo.Close()
assert.NoError(t, err, "should be able to close") assert.NoError(t, err, "should be able to close")