Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Don't sort plugin mounts slice
This was added as part of a53930a with
the intent to sort the mounts in the plugin config, but this was sorting
*all* the mounts from the default OCI spec which is problematic.

In reality we don't need to sort this because we are only adding a
self-binded mount to flag it as rshared.

We may want to look at sorting the plugin mounts before they are added
to the OCI spec in the future, but for now I think the existing behavior
is fine since the plugin author has control of the order (except for the
propagated mount).

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
  • Loading branch information
cpuguy83 committed Mar 28, 2018
commit ec90839ca302ca53a7d55e4c7f79e7b4779f5e15
32 changes: 32 additions & 0 deletions 32 integration-cli/fixtures/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,38 @@ func makePluginBundle(inPath string, opts ...CreateOpt) (io.ReadCloser, error) {
if err := os.MkdirAll(filepath.Join(inPath, "rootfs", filepath.Dir(p.Entrypoint[0])), 0755); err != nil {
return nil, errors.Wrap(err, "error creating plugin rootfs dir")
}

// Ensure the mount target paths exist
for _, m := range p.Mounts {
var stat os.FileInfo
if m.Source != nil {
stat, err = os.Stat(*m.Source)
if err != nil && !os.IsNotExist(err) {
return nil, err
}
}

if stat == nil || stat.IsDir() {
var mode os.FileMode = 0755
if stat != nil {
mode = stat.Mode()
}
if err := os.MkdirAll(filepath.Join(inPath, "rootfs", m.Destination), mode); err != nil {
return nil, errors.Wrap(err, "error preparing plugin mount destination path")
}
} else {
if err := os.MkdirAll(filepath.Join(inPath, "rootfs", filepath.Dir(m.Destination)), 0755); err != nil {
return nil, errors.Wrap(err, "error preparing plugin mount destination dir")
}
f, err := os.Create(filepath.Join(inPath, "rootfs", m.Destination))
if err != nil && !os.IsExist(err) {
return nil, errors.Wrap(err, "error preparing plugin mount destination file")
}
if f != nil {
f.Close()
}
}
}
if err := archive.NewDefaultArchiver().CopyFileWithTar(cfg.binPath, filepath.Join(inPath, "rootfs", p.Entrypoint[0])); err != nil {
return nil, errors.Wrap(err, "error copying plugin binary to rootfs path")
}
Expand Down
1 change: 1 addition & 0 deletions 1 integration/plugin/volumes/cmd/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package cmd
19 changes: 19 additions & 0 deletions 19 integration/plugin/volumes/cmd/dummy/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import (
"net"
"net/http"
)

func main() {
l, err := net.Listen("unix", "/run/docker/plugins/plugin.sock")
if err != nil {
panic(err)
}

server := http.Server{
Addr: l.Addr().String(),
Handler: http.NewServeMux(),
}
server.Serve(l)
}
1 change: 1 addition & 0 deletions 1 integration/plugin/volumes/cmd/dummy/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package main
73 changes: 73 additions & 0 deletions 73 integration/plugin/volumes/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package volumes

import (
"context"
"os"
"os/exec"
"path/filepath"
"testing"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/integration-cli/fixtures/plugin"
"github.com/docker/docker/pkg/locker"
"github.com/pkg/errors"
)

var pluginBuildLock = locker.New()

// ensurePlugin makes the that a plugin binary has been installed on the system.
// Plugins that have not been installed are built from `cmd/<name>`.
func ensurePlugin(t *testing.T, name string) string {
pluginBuildLock.Lock(name)
defer pluginBuildLock.Unlock(name)

goPath := os.Getenv("GOPATH")
if goPath == "" {
goPath = "/go"
}
installPath := filepath.Join(goPath, "bin", name)
if _, err := os.Stat(installPath); err == nil {
return installPath
}

goBin, err := exec.LookPath("go")
if err != nil {
t.Fatal(err)
}

cmd := exec.Command(goBin, "build", "-o", installPath, "./"+filepath.Join("cmd", name))
cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatal(errors.Wrapf(err, "error building basic plugin bin: %s", string(out)))
}

return installPath
}

func withSockPath(name string) func(*plugin.Config) {
return func(cfg *plugin.Config) {
cfg.Interface.Socket = name
}
}

func createPlugin(t *testing.T, client plugin.CreateClient, alias, bin string, opts ...plugin.CreateOpt) {
pluginBin := ensurePlugin(t, bin)

opts = append(opts, withSockPath("plugin.sock"))
opts = append(opts, plugin.WithBinary(pluginBin))

ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
err := plugin.Create(ctx, client, alias, opts...)
cancel()

if err != nil {
t.Fatal(err)
}
}

func asVolumeDriver(cfg *plugin.Config) {
cfg.Interface.Types = []types.PluginInterfaceType{
{Capability: "volumedriver", Prefix: "docker", Version: "1.0"},
}
}
34 changes: 34 additions & 0 deletions 34 integration/plugin/volumes/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package volumes // import "github.com/docker/docker/integration/plugin/volumes"

import (
"fmt"
"os"
"testing"

"github.com/docker/docker/internal/test/environment"
)

var (
testEnv *environment.Execution
)

const dockerdBinary = "dockerd"

func TestMain(m *testing.M) {
var err error
testEnv, err = environment.New()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if testEnv.OSType != "linux" {
os.Exit(0)
}
err = environment.EnsureFrozenImagesLinux(testEnv)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
testEnv.Print()
os.Exit(m.Run())
}
56 changes: 56 additions & 0 deletions 56 integration/plugin/volumes/mounts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package volumes

import (
"context"
"io/ioutil"
"os"
"testing"

"github.com/docker/docker/api/types"
"github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/integration-cli/fixtures/plugin"
"github.com/gotestyourself/gotestyourself/assert"
)

// TestPluginWithDevMounts tests very specific regression caused by mounts ordering
// (sorted in the daemon). See #36698
func TestPluginWithDevMounts(t *testing.T) {
t.Parallel()

d := daemon.New(t, "", dockerdBinary, daemon.Config{})
d.Start(t, "--iptables=false")
defer d.Stop(t)

client, err := d.NewClient()
assert.Assert(t, err)
ctx := context.Background()

testDir, err := ioutil.TempDir("", "test-dir")
assert.Assert(t, err)
defer os.RemoveAll(testDir)

createPlugin(t, client, "test", "dummy", asVolumeDriver, func(c *plugin.Config) {
root := "/"
dev := "/dev"
mounts := []types.PluginMount{
{Type: "bind", Source: &root, Destination: "/host", Options: []string{"rbind"}},
{Type: "bind", Source: &dev, Destination: "/dev", Options: []string{"rbind"}},
{Type: "bind", Source: &testDir, Destination: "/etc/foo", Options: []string{"rbind"}},
}
c.PluginConfig.Mounts = append(c.PluginConfig.Mounts, mounts...)
c.PropagatedMount = "/propagated"
c.Network = types.PluginConfigNetwork{Type: "host"}
c.IpcHost = true
})

err = client.PluginEnable(ctx, "test", types.PluginEnableOptions{Timeout: 30})
assert.Assert(t, err)
defer func() {
err := client.PluginRemove(ctx, "test", types.PluginRemoveOptions{Force: true})
assert.Check(t, err)
}()

p, _, err := client.PluginInspectWithRaw(ctx, "test")
assert.Assert(t, err)
assert.Assert(t, p.Enabled)
}
5 changes: 0 additions & 5 deletions 5 plugin/v2/plugin_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"os"
"path/filepath"
"runtime"
"sort"
"strings"

"github.com/docker/docker/api/types"
Expand Down Expand Up @@ -138,9 +137,5 @@ func (p *Plugin) InitSpec(execRoot string) (*specs.Spec, error) {
p.modifyRuntimeSpec(&s)
}

sort.Slice(s.Mounts, func(i, j int) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my clarification: So including the OCI defaults in the sort was overwriting the explicit /dev mounts from the plugin with the OCI defaults? Even so, how did it mess up the host /dev?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it's adding things like a custom /dev/pts for the plugin, but if the host /dev is mounted in first this causes issues.

return s.Mounts[i].Destination < s.Mounts[j].Destination
})

return &s, nil
}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.