Skip to content

Commit

Permalink
plugins: add support for plugin configs
Browse files Browse the repository at this point in the history
For now, configs specified in `daemon --init-config` and `init CONFIG` are not
available. We should fix this eventually but isn't necessary for now (and
supporting this will be annoying).
  • Loading branch information
Stebalien committed Aug 29, 2019
1 parent d2a1ce3 commit 45f5115
Show file tree
Hide file tree
Showing 12 changed files with 122 additions and 27 deletions.
16 changes: 1 addition & 15 deletions cmd/ipfs/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"math/rand"
"os"
"path/filepath"
"runtime/pprof"
"strings"
"time"
Expand Down Expand Up @@ -46,24 +45,11 @@ const (
)

func loadPlugins(repoPath string) (*loader.PluginLoader, error) {
pluginpath := filepath.Join(repoPath, "plugins")

plugins, err := loader.NewPluginLoader()
plugins, err := loader.NewPluginLoader(repoPath)
if err != nil {
return nil, fmt.Errorf("error loading preloaded plugins: %s", err)
}

// check if repo is accessible before loading plugins
ok, err := checkPermissions(repoPath)
if err != nil {
return nil, err
}
if ok {
if err := plugins.LoadDirectory(pluginpath); err != nil {
return nil, err
}
}

if err := plugins.Initialize(); err != nil {
return nil, fmt.Errorf("error initializing plugins: %s", err)
}
Expand Down
6 changes: 6 additions & 0 deletions commands/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ func (c *Context) GetNode() (*core.IpfsNode, error) {
return nil, errors.New("nil ConstructNode function")
}
c.node, err = c.ConstructNode()
if err != nil {
// Pre-load the config from the repo to avoid re-parsing it from disk.
if cfg, err := c.node.Repo.Config(); err != nil {
c.config = cfg
}
}
}
return c.node, err
}
Expand Down
3 changes: 3 additions & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ directory (by default `~/.ipfs/plugins`).

## Plugin Types

Plugins can implement one or more plugin types, defined in the
[plugin](https://godoc.org/github.com/ipfs/go-ipfs/plugin) package.

### IPLD

IPLD plugins add support for additional formats to `ipfs dag` and other IPLD
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ require (
github.com/ipfs/go-ipfs-blockstore v0.1.0
github.com/ipfs/go-ipfs-chunker v0.0.1
github.com/ipfs/go-ipfs-cmds v0.1.0
github.com/ipfs/go-ipfs-config v0.0.6
github.com/ipfs/go-ipfs-config v0.0.11
github.com/ipfs/go-ipfs-ds-help v0.0.1
github.com/ipfs/go-ipfs-exchange-interface v0.0.1
github.com/ipfs/go-ipfs-exchange-offline v0.0.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcB
github.com/ipfs/go-ipfs-cmds v0.1.0 h1:0CEde9EcxByej8+L6d1PST57J4ambRPyCTjLG5Ymou8=
github.com/ipfs/go-ipfs-cmds v0.1.0/go.mod h1:TiK4e7/V31tuEb8YWDF8lN3qrnDH+BS7ZqWIeYJlAs8=
github.com/ipfs/go-ipfs-config v0.0.5/go.mod h1:IGkVTacurWv9WFKc7IBPjHGM/7hi6+PEClqUb/l2BIM=
github.com/ipfs/go-ipfs-config v0.0.6 h1:jzK9Tl8S0oWBir3F5ObtGgnHRPdqQ0MYiCmwXtV3Ps4=
github.com/ipfs/go-ipfs-config v0.0.6/go.mod h1:IGkVTacurWv9WFKc7IBPjHGM/7hi6+PEClqUb/l2BIM=
github.com/ipfs/go-ipfs-config v0.0.11 h1:5/4nas2CQXiKr2/MLxU24GDGTBvtstQIQezuk7ltOQQ=
github.com/ipfs/go-ipfs-config v0.0.11/go.mod h1:wveA8UT5ywN26oKStByzmz1CO6cXwLKKM6Jn/Hfw08I=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
Expand Down
34 changes: 30 additions & 4 deletions plugin/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package loader
import (
"fmt"
"os"
"path/filepath"
"strings"

config "github.com/ipfs/go-ipfs-config"
cserialize "github.com/ipfs/go-ipfs-config/serialize"
coredag "github.com/ipfs/go-ipfs/core/coredag"
plugin "github.com/ipfs/go-ipfs/plugin"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
Expand Down Expand Up @@ -83,16 +86,32 @@ type PluginLoader struct {
state loaderState
plugins map[string]plugin.Plugin
started []plugin.Plugin
config config.Plugins
repo string
}

// NewPluginLoader creates new plugin loader
func NewPluginLoader() (*PluginLoader, error) {
loader := &PluginLoader{plugins: make(map[string]plugin.Plugin, len(preloadPlugins))}
func NewPluginLoader(repo string) (*PluginLoader, error) {
loader := &PluginLoader{plugins: make(map[string]plugin.Plugin, len(preloadPlugins)), repo: repo}
if repo != "" {
cfg, err := cserialize.Load(filepath.Join(repo, config.DefaultConfigFile))
switch err {
case cserialize.ErrNotInitialized:
case nil:
loader.config = cfg.Plugins
default:
return nil, err
}
}
for _, v := range preloadPlugins {
if err := loader.Load(v); err != nil {
return nil, err
}
}

if err := loader.LoadDirectory(filepath.Join(repo, "plugins")); err != nil {
return nil, err
}
return loader, nil
}

Expand Down Expand Up @@ -125,6 +144,10 @@ func (loader *PluginLoader) Load(pl plugin.Plugin) error {
"while trying to load dynamically: %s",
name, ppl.Version(), pl.Version())
}
if loader.config.Plugins[name].Disabled {
log.Infof("not loading disabled plugin %s", name)
return nil
}
loader.plugins[name] = pl
return nil
}
Expand Down Expand Up @@ -164,8 +187,11 @@ func (loader *PluginLoader) Initialize() error {
if err := loader.transition(loaderLoading, loaderInitializing); err != nil {
return err
}
for _, p := range loader.plugins {
err := p.Init()
for name, p := range loader.plugins {
err := p.Init(&plugin.Environment{
Repo: loader.repo,
Config: loader.config.Plugins[name].Config,
})
if err != nil {
loader.state = loaderFailed
return err
Expand Down
15 changes: 14 additions & 1 deletion plugin/plugin.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
package plugin

// Environment is the environment passed into the plugin on init.
type Environment struct {
// Path to the IPFS repo.
Repo string

// The plugin's config, if specified.
Config interface{}
}

// Plugin is base interface for all kinds of go-ipfs plugins
// It will be included in interfaces of different Plugins
type Plugin interface {
// Name should return unique name of the plugin
Name() string

// Version returns current version of the plugin
Version() string

// Init is called once when the Plugin is being loaded
Init() error
// The plugin is passed an environment containing the path to the
// (possibly uninitialized) IPFS repo and the plugin's config.
Init(env *Environment) error
}
2 changes: 1 addition & 1 deletion plugin/plugins/badgerds/badgerds.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (*badgerdsPlugin) Version() string {
return "0.1.0"
}

func (*badgerdsPlugin) Init() error {
func (*badgerdsPlugin) Init(_ *plugin.Environment) error {
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion plugin/plugins/flatfs/flatfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (*flatfsPlugin) Version() string {
return "0.1.0"
}

func (*flatfsPlugin) Init() error {
func (*flatfsPlugin) Init(_ *plugin.Environment) error {
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion plugin/plugins/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (*gitPlugin) Version() string {
return "0.0.1"
}

func (*gitPlugin) Init() error {
func (*gitPlugin) Init(_ *plugin.Environment) error {
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion plugin/plugins/levelds/levelds.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (*leveldsPlugin) Version() string {
return "0.1.0"
}

func (*leveldsPlugin) Init() error {
func (*leveldsPlugin) Init(_ *plugin.Environment) error {
return nil
}

Expand Down
61 changes: 61 additions & 0 deletions test/sharness/t0280-plugin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ test_description="Test plugin loading"

. lib/test-lib.sh

if ! test_have_prereq PLUGIN; then
skip_all='skipping plugin tests, plugins not available'

test_done
fi

test_init_ipfs

test_expect_success "ipfs id succeeds" '
Expand All @@ -28,4 +34,59 @@ test_expect_success "cleanup bad plugin" '
rm "$IPFS_PATH/plugins/foo.so"
'

test_expect_success "install test plugin" '
go build \
-asmflags=all="-trimpath=${GOPATH}" -gcflags=all="-trimpath=${GOPATH}" \
-buildmode=plugin -o "$IPFS_PATH/plugins/example.so" ../t0280-plugin-data/example.go &&
chmod +x "$IPFS_PATH/plugins/example.so"
'

test_plugin() {
local loads="$1"
local repo="$2"
local config="$3"

rm -f id_raw_output id_output id_output_expected

test_expect_success "id runs" '
ipfs id 2>id_raw_output >/dev/null
'

test_expect_success "filter test plugin output" '
sed -ne "s/^testplugin //p" id_raw_output >id_output
'

if [ "$loads" != "true" ]; then
test_expect_success "plugin doesn't load" '
test_must_be_empty id_output
'
else
test_expect_success "plugin produces the correct output" '
echo "$repo" >id_output_expected &&
echo "$config" >>id_output_expected &&
test_cmp id_output id_output_expected
'
fi
}

test_plugin true "$IPFS_PATH" "<nil>"

test_expect_success "disable the plugin" '
ipfs config --json Plugins.Plugins.test-plugin.Disabled true
'

test_plugin false

test_expect_success "re-enable the plugin" '
ipfs config --json Plugins.Plugins.test-plugin.Disabled false
'

test_plugin true "$IPFS_PATH" "<nil>"

test_expect_success "configure the plugin" '
ipfs config Plugins.Plugins.test-plugin.Config foobar
'

test_plugin true "$IPFS_PATH" "foobar"

test_done

0 comments on commit 45f5115

Please sign in to comment.