Also enables `PropagatedMount` for graphdrivers.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
| ... | ... |
@@ -154,10 +154,12 @@ func GetDriver(name, home string, options []string, uidMaps, gidMaps []idtools.I |
| 154 | 154 |
if initFunc, exists := drivers[name]; exists {
|
| 155 | 155 |
return initFunc(filepath.Join(home, name), options, uidMaps, gidMaps) |
| 156 | 156 |
} |
| 157 |
- if pluginDriver, err := lookupPlugin(name, home, options, pg); err == nil {
|
|
| 157 |
+ |
|
| 158 |
+ pluginDriver, err := lookupPlugin(name, home, options, pg) |
|
| 159 |
+ if err == nil {
|
|
| 158 | 160 |
return pluginDriver, nil |
| 159 | 161 |
} |
| 160 |
- logrus.Errorf("Failed to GetDriver graph %s %s", name, home)
|
|
| 162 |
+ logrus.WithError(err).WithField("driver", name).WithField("home-dir", home).Error("Failed to GetDriver graph")
|
|
| 161 | 163 |
return nil, ErrNotSupported |
| 162 | 164 |
} |
| 163 | 165 |
|
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"path/filepath" |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/pkg/plugingetter" |
| 9 |
+ "github.com/docker/docker/plugin/v2" |
|
| 9 | 10 |
) |
| 10 | 11 |
|
| 11 | 12 |
type pluginClient interface {
|
| ... | ... |
@@ -26,6 +27,13 @@ func lookupPlugin(name, home string, opts []string, pg plugingetter.PluginGetter |
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 | 28 |
func newPluginDriver(name, home string, opts []string, pl plugingetter.CompatPlugin) (Driver, error) {
|
| 29 |
- proxy := &graphDriverProxy{name, pl.Client(), pl}
|
|
| 29 |
+ if !pl.IsV1() {
|
|
| 30 |
+ if p, ok := pl.(*v2.Plugin); ok {
|
|
| 31 |
+ if p.PropagatedMount != "" {
|
|
| 32 |
+ home = p.PluginObj.Config.PropagatedMount |
|
| 33 |
+ } |
|
| 34 |
+ } |
|
| 35 |
+ } |
|
| 36 |
+ proxy := &graphDriverProxy{name, pl}
|
|
| 30 | 37 |
return proxy, proxy.Init(filepath.Join(home, name), opts) |
| 31 | 38 |
} |
| ... | ... |
@@ -4,15 +4,15 @@ import ( |
| 4 | 4 |
"errors" |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"io" |
| 7 |
+ "path/filepath" |
|
| 7 | 8 |
|
| 8 | 9 |
"github.com/docker/docker/pkg/archive" |
| 9 | 10 |
"github.com/docker/docker/pkg/plugingetter" |
| 10 | 11 |
) |
| 11 | 12 |
|
| 12 | 13 |
type graphDriverProxy struct {
|
| 13 |
- name string |
|
| 14 |
- client pluginClient |
|
| 15 |
- p plugingetter.CompatPlugin |
|
| 14 |
+ name string |
|
| 15 |
+ p plugingetter.CompatPlugin |
|
| 16 | 16 |
} |
| 17 | 17 |
|
| 18 | 18 |
type graphDriverRequest struct {
|
| ... | ... |
@@ -48,7 +48,7 @@ func (d *graphDriverProxy) Init(home string, opts []string) error {
|
| 48 | 48 |
Opts: opts, |
| 49 | 49 |
} |
| 50 | 50 |
var ret graphDriverResponse |
| 51 |
- if err := d.client.Call("GraphDriver.Init", args, &ret); err != nil {
|
|
| 51 |
+ if err := d.p.Client().Call("GraphDriver.Init", args, &ret); err != nil {
|
|
| 52 | 52 |
return err |
| 53 | 53 |
} |
| 54 | 54 |
if ret.Err != "" {
|
| ... | ... |
@@ -73,7 +73,7 @@ func (d *graphDriverProxy) CreateReadWrite(id, parent string, opts *CreateOpts) |
| 73 | 73 |
MountLabel: mountLabel, |
| 74 | 74 |
} |
| 75 | 75 |
var ret graphDriverResponse |
| 76 |
- if err := d.client.Call("GraphDriver.CreateReadWrite", args, &ret); err != nil {
|
|
| 76 |
+ if err := d.p.Client().Call("GraphDriver.CreateReadWrite", args, &ret); err != nil {
|
|
| 77 | 77 |
return err |
| 78 | 78 |
} |
| 79 | 79 |
if ret.Err != "" {
|
| ... | ... |
@@ -93,7 +93,7 @@ func (d *graphDriverProxy) Create(id, parent string, opts *CreateOpts) error {
|
| 93 | 93 |
MountLabel: mountLabel, |
| 94 | 94 |
} |
| 95 | 95 |
var ret graphDriverResponse |
| 96 |
- if err := d.client.Call("GraphDriver.Create", args, &ret); err != nil {
|
|
| 96 |
+ if err := d.p.Client().Call("GraphDriver.Create", args, &ret); err != nil {
|
|
| 97 | 97 |
return err |
| 98 | 98 |
} |
| 99 | 99 |
if ret.Err != "" {
|
| ... | ... |
@@ -105,7 +105,7 @@ func (d *graphDriverProxy) Create(id, parent string, opts *CreateOpts) error {
|
| 105 | 105 |
func (d *graphDriverProxy) Remove(id string) error {
|
| 106 | 106 |
args := &graphDriverRequest{ID: id}
|
| 107 | 107 |
var ret graphDriverResponse |
| 108 |
- if err := d.client.Call("GraphDriver.Remove", args, &ret); err != nil {
|
|
| 108 |
+ if err := d.p.Client().Call("GraphDriver.Remove", args, &ret); err != nil {
|
|
| 109 | 109 |
return err |
| 110 | 110 |
} |
| 111 | 111 |
if ret.Err != "" {
|
| ... | ... |
@@ -120,20 +120,20 @@ func (d *graphDriverProxy) Get(id, mountLabel string) (string, error) {
|
| 120 | 120 |
MountLabel: mountLabel, |
| 121 | 121 |
} |
| 122 | 122 |
var ret graphDriverResponse |
| 123 |
- if err := d.client.Call("GraphDriver.Get", args, &ret); err != nil {
|
|
| 123 |
+ if err := d.p.Client().Call("GraphDriver.Get", args, &ret); err != nil {
|
|
| 124 | 124 |
return "", err |
| 125 | 125 |
} |
| 126 | 126 |
var err error |
| 127 | 127 |
if ret.Err != "" {
|
| 128 | 128 |
err = errors.New(ret.Err) |
| 129 | 129 |
} |
| 130 |
- return ret.Dir, err |
|
| 130 |
+ return filepath.Join(d.p.BasePath(), ret.Dir), err |
|
| 131 | 131 |
} |
| 132 | 132 |
|
| 133 | 133 |
func (d *graphDriverProxy) Put(id string) error {
|
| 134 | 134 |
args := &graphDriverRequest{ID: id}
|
| 135 | 135 |
var ret graphDriverResponse |
| 136 |
- if err := d.client.Call("GraphDriver.Put", args, &ret); err != nil {
|
|
| 136 |
+ if err := d.p.Client().Call("GraphDriver.Put", args, &ret); err != nil {
|
|
| 137 | 137 |
return err |
| 138 | 138 |
} |
| 139 | 139 |
if ret.Err != "" {
|
| ... | ... |
@@ -145,7 +145,7 @@ func (d *graphDriverProxy) Put(id string) error {
|
| 145 | 145 |
func (d *graphDriverProxy) Exists(id string) bool {
|
| 146 | 146 |
args := &graphDriverRequest{ID: id}
|
| 147 | 147 |
var ret graphDriverResponse |
| 148 |
- if err := d.client.Call("GraphDriver.Exists", args, &ret); err != nil {
|
|
| 148 |
+ if err := d.p.Client().Call("GraphDriver.Exists", args, &ret); err != nil {
|
|
| 149 | 149 |
return false |
| 150 | 150 |
} |
| 151 | 151 |
return ret.Exists |
| ... | ... |
@@ -154,7 +154,7 @@ func (d *graphDriverProxy) Exists(id string) bool {
|
| 154 | 154 |
func (d *graphDriverProxy) Status() [][2]string {
|
| 155 | 155 |
args := &graphDriverRequest{}
|
| 156 | 156 |
var ret graphDriverResponse |
| 157 |
- if err := d.client.Call("GraphDriver.Status", args, &ret); err != nil {
|
|
| 157 |
+ if err := d.p.Client().Call("GraphDriver.Status", args, &ret); err != nil {
|
|
| 158 | 158 |
return nil |
| 159 | 159 |
} |
| 160 | 160 |
return ret.Status |
| ... | ... |
@@ -165,7 +165,7 @@ func (d *graphDriverProxy) GetMetadata(id string) (map[string]string, error) {
|
| 165 | 165 |
ID: id, |
| 166 | 166 |
} |
| 167 | 167 |
var ret graphDriverResponse |
| 168 |
- if err := d.client.Call("GraphDriver.GetMetadata", args, &ret); err != nil {
|
|
| 168 |
+ if err := d.p.Client().Call("GraphDriver.GetMetadata", args, &ret); err != nil {
|
|
| 169 | 169 |
return nil, err |
| 170 | 170 |
} |
| 171 | 171 |
if ret.Err != "" {
|
| ... | ... |
@@ -184,7 +184,7 @@ func (d *graphDriverProxy) Cleanup() error {
|
| 184 | 184 |
|
| 185 | 185 |
args := &graphDriverRequest{}
|
| 186 | 186 |
var ret graphDriverResponse |
| 187 |
- if err := d.client.Call("GraphDriver.Cleanup", args, &ret); err != nil {
|
|
| 187 |
+ if err := d.p.Client().Call("GraphDriver.Cleanup", args, &ret); err != nil {
|
|
| 188 | 188 |
return nil |
| 189 | 189 |
} |
| 190 | 190 |
if ret.Err != "" {
|
| ... | ... |
@@ -198,7 +198,7 @@ func (d *graphDriverProxy) Diff(id, parent string) (io.ReadCloser, error) {
|
| 198 | 198 |
ID: id, |
| 199 | 199 |
Parent: parent, |
| 200 | 200 |
} |
| 201 |
- body, err := d.client.Stream("GraphDriver.Diff", args)
|
|
| 201 |
+ body, err := d.p.Client().Stream("GraphDriver.Diff", args)
|
|
| 202 | 202 |
if err != nil {
|
| 203 | 203 |
return nil, err |
| 204 | 204 |
} |
| ... | ... |
@@ -211,7 +211,7 @@ func (d *graphDriverProxy) Changes(id, parent string) ([]archive.Change, error) |
| 211 | 211 |
Parent: parent, |
| 212 | 212 |
} |
| 213 | 213 |
var ret graphDriverResponse |
| 214 |
- if err := d.client.Call("GraphDriver.Changes", args, &ret); err != nil {
|
|
| 214 |
+ if err := d.p.Client().Call("GraphDriver.Changes", args, &ret); err != nil {
|
|
| 215 | 215 |
return nil, err |
| 216 | 216 |
} |
| 217 | 217 |
if ret.Err != "" {
|
| ... | ... |
@@ -223,7 +223,7 @@ func (d *graphDriverProxy) Changes(id, parent string) ([]archive.Change, error) |
| 223 | 223 |
|
| 224 | 224 |
func (d *graphDriverProxy) ApplyDiff(id, parent string, diff io.Reader) (int64, error) {
|
| 225 | 225 |
var ret graphDriverResponse |
| 226 |
- if err := d.client.SendFile(fmt.Sprintf("GraphDriver.ApplyDiff?id=%s&parent=%s", id, parent), diff, &ret); err != nil {
|
|
| 226 |
+ if err := d.p.Client().SendFile(fmt.Sprintf("GraphDriver.ApplyDiff?id=%s&parent=%s", id, parent), diff, &ret); err != nil {
|
|
| 227 | 227 |
return -1, err |
| 228 | 228 |
} |
| 229 | 229 |
if ret.Err != "" {
|
| ... | ... |
@@ -238,7 +238,7 @@ func (d *graphDriverProxy) DiffSize(id, parent string) (int64, error) {
|
| 238 | 238 |
Parent: parent, |
| 239 | 239 |
} |
| 240 | 240 |
var ret graphDriverResponse |
| 241 |
- if err := d.client.Call("GraphDriver.DiffSize", args, &ret); err != nil {
|
|
| 241 |
+ if err := d.p.Client().Call("GraphDriver.DiffSize", args, &ret); err != nil {
|
|
| 242 | 242 |
return -1, err |
| 243 | 243 |
} |
| 244 | 244 |
if ret.Err != "" {
|
| ... | ... |
@@ -235,6 +235,24 @@ func (s *DockerDaemonSuite) TestVolumePlugin(c *check.C) {
|
| 235 | 235 |
c.Assert(exists, checker.Equals, true) |
| 236 | 236 |
} |
| 237 | 237 |
|
| 238 |
+func (s *DockerDaemonSuite) TestGraphdriverPlugin(c *check.C) {
|
|
| 239 |
+ testRequires(c, Network, IsAmd64, DaemonIsLinux, overlaySupported) |
|
| 240 |
+ |
|
| 241 |
+ s.d.Start(c) |
|
| 242 |
+ |
|
| 243 |
+ // install the plugin |
|
| 244 |
+ plugin := "cpuguy83/docker-overlay2-graphdriver-plugin" |
|
| 245 |
+ out, err := s.d.Cmd("plugin", "install", "--grant-all-permissions", plugin)
|
|
| 246 |
+ c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
| 247 |
+ |
|
| 248 |
+ // restart the daemon with the plugin set as the storage driver |
|
| 249 |
+ s.d.Restart(c, "-s", plugin) |
|
| 250 |
+ |
|
| 251 |
+ // run a container |
|
| 252 |
+ out, err = s.d.Cmd("run", "--rm", "busybox", "true") // this will pull busybox using the plugin
|
|
| 253 |
+ c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
| 254 |
+} |
|
| 255 |
+ |
|
| 238 | 256 |
func existsMountpointWithPrefix(mountpointPrefix string) (bool, error) {
|
| 239 | 257 |
mounts, err := mount.GetMounts() |
| 240 | 258 |
if err != nil {
|
| ... | ... |
@@ -3,7 +3,9 @@ |
| 3 | 3 |
package main |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "bytes" |
|
| 6 | 7 |
"io/ioutil" |
| 8 |
+ "os/exec" |
|
| 7 | 9 |
"strings" |
| 8 | 10 |
|
| 9 | 11 |
"github.com/docker/docker/pkg/sysinfo" |
| ... | ... |
@@ -122,6 +124,17 @@ var ( |
| 122 | 122 |
}, |
| 123 | 123 |
"Test cannot be run without a kernel (4.3+) supporting ambient capabilities", |
| 124 | 124 |
} |
| 125 |
+ overlaySupported = testRequirement{
|
|
| 126 |
+ func() bool {
|
|
| 127 |
+ cmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "cat /proc/filesystems") |
|
| 128 |
+ out, err := cmd.CombinedOutput() |
|
| 129 |
+ if err != nil {
|
|
| 130 |
+ return false |
|
| 131 |
+ } |
|
| 132 |
+ return bytes.Contains(out, []byte("overlay\n"))
|
|
| 133 |
+ }, |
|
| 134 |
+ "Test cannot be run wihtout suppport for ovelayfs", |
|
| 135 |
+ } |
|
| 125 | 136 |
) |
| 126 | 137 |
|
| 127 | 138 |
func init() {
|
| ... | ... |
@@ -156,7 +156,7 @@ func (pm *Manager) reload() error {
|
| 156 | 156 |
|
| 157 | 157 |
// We should only enable rootfs propagation for certain plugin types that need it. |
| 158 | 158 |
for _, typ := range p.PluginObj.Config.Interface.Types {
|
| 159 |
- if typ.Capability == "volumedriver" && typ.Prefix == "docker" && strings.HasPrefix(typ.Version, "1.") {
|
|
| 159 |
+ if (typ.Capability == "volumedriver" || typ.Capability == "graphdriver") && typ.Prefix == "docker" && strings.HasPrefix(typ.Version, "1.") {
|
|
| 160 | 160 |
if p.PluginObj.Config.PropagatedMount != "" {
|
| 161 | 161 |
// TODO: sanitize PropagatedMount and prevent breakout |
| 162 | 162 |
p.PropagatedMount = filepath.Join(p.Rootfs, p.PluginObj.Config.PropagatedMount) |