diff --git a/daemon/graphdriver/driver.go b/daemon/graphdriver/driver.go index cc548710a2..dc41d780be 100644 --- a/daemon/graphdriver/driver.go +++ b/daemon/graphdriver/driver.go @@ -154,10 +154,12 @@ func GetDriver(name, home string, options []string, uidMaps, gidMaps []idtools.I if initFunc, exists := drivers[name]; exists { return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) } - if pluginDriver, err := lookupPlugin(name, home, options, pg); err == nil { + + pluginDriver, err := lookupPlugin(name, home, options, pg) + if err == nil { return pluginDriver, nil } - logrus.Errorf("Failed to GetDriver graph %s %s", name, home) + logrus.WithError(err).WithField("driver", name).WithField("home-dir", home).Error("Failed to GetDriver graph") return nil, ErrNotSupported } diff --git a/daemon/graphdriver/plugin.go b/daemon/graphdriver/plugin.go index 6a79c29681..4f2f09d72f 100644 --- a/daemon/graphdriver/plugin.go +++ b/daemon/graphdriver/plugin.go @@ -6,6 +6,7 @@ import ( "path/filepath" "github.com/docker/docker/pkg/plugingetter" + "github.com/docker/docker/plugin/v2" ) type pluginClient interface { @@ -26,6 +27,13 @@ func lookupPlugin(name, home string, opts []string, pg plugingetter.PluginGetter } func newPluginDriver(name, home string, opts []string, pl plugingetter.CompatPlugin) (Driver, error) { - proxy := &graphDriverProxy{name, pl.Client(), pl} + if !pl.IsV1() { + if p, ok := pl.(*v2.Plugin); ok { + if p.PropagatedMount != "" { + home = p.PluginObj.Config.PropagatedMount + } + } + } + proxy := &graphDriverProxy{name, pl} return proxy, proxy.Init(filepath.Join(home, name), opts) } diff --git a/daemon/graphdriver/proxy.go b/daemon/graphdriver/proxy.go index 713124b442..f037ab736e 100644 --- a/daemon/graphdriver/proxy.go +++ b/daemon/graphdriver/proxy.go @@ -4,15 +4,15 @@ import ( "errors" "fmt" "io" + "path/filepath" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/plugingetter" ) type graphDriverProxy struct { - name string - client pluginClient - p plugingetter.CompatPlugin + name string + p plugingetter.CompatPlugin } type graphDriverRequest struct { @@ -48,7 +48,7 @@ func (d *graphDriverProxy) Init(home string, opts []string) error { Opts: opts, } var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Init", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Init", args, &ret); err != nil { return err } if ret.Err != "" { @@ -73,7 +73,7 @@ func (d *graphDriverProxy) CreateReadWrite(id, parent string, opts *CreateOpts) MountLabel: mountLabel, } var ret graphDriverResponse - if err := d.client.Call("GraphDriver.CreateReadWrite", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.CreateReadWrite", args, &ret); err != nil { return err } if ret.Err != "" { @@ -93,7 +93,7 @@ func (d *graphDriverProxy) Create(id, parent string, opts *CreateOpts) error { MountLabel: mountLabel, } var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Create", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Create", args, &ret); err != nil { return err } if ret.Err != "" { @@ -105,7 +105,7 @@ func (d *graphDriverProxy) Create(id, parent string, opts *CreateOpts) error { func (d *graphDriverProxy) Remove(id string) error { args := &graphDriverRequest{ID: id} var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Remove", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Remove", args, &ret); err != nil { return err } if ret.Err != "" { @@ -120,20 +120,20 @@ func (d *graphDriverProxy) Get(id, mountLabel string) (string, error) { MountLabel: mountLabel, } var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Get", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Get", args, &ret); err != nil { return "", err } var err error if ret.Err != "" { err = errors.New(ret.Err) } - return ret.Dir, err + return filepath.Join(d.p.BasePath(), ret.Dir), err } func (d *graphDriverProxy) Put(id string) error { args := &graphDriverRequest{ID: id} var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Put", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Put", args, &ret); err != nil { return err } if ret.Err != "" { @@ -145,7 +145,7 @@ func (d *graphDriverProxy) Put(id string) error { func (d *graphDriverProxy) Exists(id string) bool { args := &graphDriverRequest{ID: id} var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Exists", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Exists", args, &ret); err != nil { return false } return ret.Exists @@ -154,7 +154,7 @@ func (d *graphDriverProxy) Exists(id string) bool { func (d *graphDriverProxy) Status() [][2]string { args := &graphDriverRequest{} var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Status", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Status", args, &ret); err != nil { return nil } return ret.Status @@ -165,7 +165,7 @@ func (d *graphDriverProxy) GetMetadata(id string) (map[string]string, error) { ID: id, } var ret graphDriverResponse - if err := d.client.Call("GraphDriver.GetMetadata", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.GetMetadata", args, &ret); err != nil { return nil, err } if ret.Err != "" { @@ -184,7 +184,7 @@ func (d *graphDriverProxy) Cleanup() error { args := &graphDriverRequest{} var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Cleanup", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Cleanup", args, &ret); err != nil { return nil } if ret.Err != "" { @@ -198,7 +198,7 @@ func (d *graphDriverProxy) Diff(id, parent string) (io.ReadCloser, error) { ID: id, Parent: parent, } - body, err := d.client.Stream("GraphDriver.Diff", args) + body, err := d.p.Client().Stream("GraphDriver.Diff", args) if err != nil { return nil, err } @@ -211,7 +211,7 @@ func (d *graphDriverProxy) Changes(id, parent string) ([]archive.Change, error) Parent: parent, } var ret graphDriverResponse - if err := d.client.Call("GraphDriver.Changes", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.Changes", args, &ret); err != nil { return nil, err } if ret.Err != "" { @@ -223,7 +223,7 @@ func (d *graphDriverProxy) Changes(id, parent string) ([]archive.Change, error) func (d *graphDriverProxy) ApplyDiff(id, parent string, diff io.Reader) (int64, error) { var ret graphDriverResponse - if err := d.client.SendFile(fmt.Sprintf("GraphDriver.ApplyDiff?id=%s&parent=%s", id, parent), diff, &ret); err != nil { + if err := d.p.Client().SendFile(fmt.Sprintf("GraphDriver.ApplyDiff?id=%s&parent=%s", id, parent), diff, &ret); err != nil { return -1, err } if ret.Err != "" { @@ -238,7 +238,7 @@ func (d *graphDriverProxy) DiffSize(id, parent string) (int64, error) { Parent: parent, } var ret graphDriverResponse - if err := d.client.Call("GraphDriver.DiffSize", args, &ret); err != nil { + if err := d.p.Client().Call("GraphDriver.DiffSize", args, &ret); err != nil { return -1, err } if ret.Err != "" { diff --git a/integration-cli/docker_cli_daemon_plugins_test.go b/integration-cli/docker_cli_daemon_plugins_test.go index 961a6fb078..947138c358 100644 --- a/integration-cli/docker_cli_daemon_plugins_test.go +++ b/integration-cli/docker_cli_daemon_plugins_test.go @@ -257,6 +257,24 @@ func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) { c.Assert(exists, checker.Equals, true) } +func (s *DockerDaemonSuite) TestGraphdriverPlugin(c *check.C) { + testRequires(c, Network, IsAmd64, DaemonIsLinux, overlaySupported) + + s.d.Start() + + // install the plugin + plugin := "cpuguy83/docker-overlay2-graphdriver-plugin" + out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", plugin) + c.Assert(err, checker.IsNil, check.Commentf(out)) + + // restart the daemon with the plugin set as the storage driver + s.d.Restart("-s", plugin) + + // run a container + out, err = s.d.Cmd("run", "--rm", "busybox", "true") // this will pull busybox using the plugin + c.Assert(err, checker.IsNil, check.Commentf(out)) +} + func existsMountpointWithPrefix(mountpointPrefix string) (bool, error) { mounts, err := mount.GetMounts() if err != nil { diff --git a/integration-cli/requirements_unix.go b/integration-cli/requirements_unix.go index 5d17c49364..53f0a6d36e 100644 --- a/integration-cli/requirements_unix.go +++ b/integration-cli/requirements_unix.go @@ -3,7 +3,9 @@ package main import ( + "bytes" "io/ioutil" + "os/exec" "strings" "github.com/docker/docker/pkg/sysinfo" @@ -122,6 +124,17 @@ var ( }, "Test cannot be run without a kernel (4.3+) supporting ambient capabilities", } + overlaySupported = testRequirement{ + func() bool { + cmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "cat /proc/filesystems") + out, err := cmd.CombinedOutput() + if err != nil { + return false + } + return bytes.Contains(out, []byte("overlay\n")) + }, + "Test cannot be run wihtout suppport for ovelayfs", + } ) func init() { diff --git a/plugin/manager.go b/plugin/manager.go index bf20990c08..aeb7cd7bca 100644 --- a/plugin/manager.go +++ b/plugin/manager.go @@ -156,7 +156,7 @@ func (pm *Manager) reload() error { // We should only enable rootfs propagation for certain plugin types that need it. for _, typ := range p.PluginObj.Config.Interface.Types { - if typ.Capability == "volumedriver" && typ.Prefix == "docker" && strings.HasPrefix(typ.Version, "1.") { + if (typ.Capability == "volumedriver" || typ.Capability == "graphdriver") && typ.Prefix == "docker" && strings.HasPrefix(typ.Version, "1.") { if p.PluginObj.Config.PropagatedMount != "" { // TODO: sanitize PropagatedMount and prevent breakout p.PropagatedMount = filepath.Join(p.Rootfs, p.PluginObj.Config.PropagatedMount)