Ensures that when a plugin is removed that it doesn't interfere with
other plugins mounts and also ensures its own mounts are cleaned up.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,79 @@ |
| 0 |
+package plugin |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "io/ioutil" |
|
| 4 |
+ "os" |
|
| 5 |
+ "path/filepath" |
|
| 6 |
+ "testing" |
|
| 7 |
+ |
|
| 8 |
+ "github.com/docker/docker/api/types" |
|
| 9 |
+ "github.com/docker/docker/pkg/mount" |
|
| 10 |
+ "github.com/docker/docker/pkg/system" |
|
| 11 |
+ "github.com/docker/docker/plugin/v2" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+func TestManagerWithPluginMounts(t *testing.T) {
|
|
| 15 |
+ root, err := ioutil.TempDir("", "test-store-with-plugin-mounts")
|
|
| 16 |
+ if err != nil {
|
|
| 17 |
+ t.Fatal(err) |
|
| 18 |
+ } |
|
| 19 |
+ defer system.EnsureRemoveAll(root) |
|
| 20 |
+ |
|
| 21 |
+ s := NewStore() |
|
| 22 |
+ managerRoot := filepath.Join(root, "manager") |
|
| 23 |
+ p1 := newTestPlugin(t, "test1", "testcap", managerRoot) |
|
| 24 |
+ |
|
| 25 |
+ p2 := newTestPlugin(t, "test2", "testcap", managerRoot) |
|
| 26 |
+ p2.PluginObj.Enabled = true |
|
| 27 |
+ |
|
| 28 |
+ m, err := NewManager( |
|
| 29 |
+ ManagerConfig{
|
|
| 30 |
+ Store: s, |
|
| 31 |
+ Root: managerRoot, |
|
| 32 |
+ ExecRoot: filepath.Join(root, "exec"), |
|
| 33 |
+ CreateExecutor: func(*Manager) (Executor, error) { return nil, nil },
|
|
| 34 |
+ LogPluginEvent: func(_, _, _ string) {},
|
|
| 35 |
+ }) |
|
| 36 |
+ if err != nil {
|
|
| 37 |
+ t.Fatal(err) |
|
| 38 |
+ } |
|
| 39 |
+ |
|
| 40 |
+ if err := s.Add(p1); err != nil {
|
|
| 41 |
+ t.Fatal(err) |
|
| 42 |
+ } |
|
| 43 |
+ if err := s.Add(p2); err != nil {
|
|
| 44 |
+ t.Fatal(err) |
|
| 45 |
+ } |
|
| 46 |
+ |
|
| 47 |
+ // Create a mount to simulate a plugin that has created it's own mounts |
|
| 48 |
+ p2Mount := filepath.Join(p2.Rootfs, "testmount") |
|
| 49 |
+ if err := os.MkdirAll(p2Mount, 0755); err != nil {
|
|
| 50 |
+ t.Fatal(err) |
|
| 51 |
+ } |
|
| 52 |
+ if err := mount.Mount("tmpfs", p2Mount, "tmpfs", ""); err != nil {
|
|
| 53 |
+ t.Fatal(err) |
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 56 |
+ if err := m.Remove(p1.Name(), &types.PluginRmConfig{ForceRemove: true}); err != nil {
|
|
| 57 |
+ t.Fatal(err) |
|
| 58 |
+ } |
|
| 59 |
+ if mounted, err := mount.Mounted(p2Mount); !mounted || err != nil {
|
|
| 60 |
+ t.Fatalf("expected %s to be mounted, err: %v", p2Mount, err)
|
|
| 61 |
+ } |
|
| 62 |
+} |
|
| 63 |
+ |
|
| 64 |
+func newTestPlugin(t *testing.T, name, cap, root string) *v2.Plugin {
|
|
| 65 |
+ rootfs := filepath.Join(root, name) |
|
| 66 |
+ if err := os.MkdirAll(rootfs, 0755); err != nil {
|
|
| 67 |
+ t.Fatal(err) |
|
| 68 |
+ } |
|
| 69 |
+ |
|
| 70 |
+ p := v2.Plugin{PluginObj: types.Plugin{Name: name}}
|
|
| 71 |
+ p.Rootfs = rootfs |
|
| 72 |
+ iType := types.PluginInterfaceType{Capability: cap, Prefix: "docker", Version: "1.0"}
|
|
| 73 |
+ i := types.PluginConfigInterface{Socket: "plugins.sock", Types: []types.PluginInterfaceType{iType}}
|
|
| 74 |
+ p.PluginObj.Config.Interface = i |
|
| 75 |
+ p.PluginObj.ID = name |
|
| 76 |
+ |
|
| 77 |
+ return &p |
|
| 78 |
+} |