In some circumstances we were not properly releasing plugin references, leading to failures in removing a plugin with no way to recover other than restarting the daemon. 1. If volume create fails (in the driver) 2. If a driver validation fails (should be rare) 3. If trying to get a plugin that does not match the passed in capability Ideally the test for 1 and 2 would just be a unit test, however the plugin interfaces are too complicated as `plugingetter` relies on github.com/pkg/plugin/Client (a concrete type), which will require spinning up services from within the unit test... it just wouldn't be a unit test at this point. I attempted to refactor this a bit, but since both libnetwork and swarmkit are reliant on `plugingetter` as well, this would not work. This really requires a re-write of the lower-level plugin management to decouple these pieces. Signed-off-by: Brian Goff <cpuguy83@gmail.com> Upstream-commit: 3816b514387efd24394f0b8e61d55502aa6ac9ac Component: engine
52 lines
1.3 KiB
Go
52 lines
1.3 KiB
Go
// +build linux
|
|
|
|
package volume
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/volume"
|
|
"github.com/docker/docker/integration-cli/daemon"
|
|
)
|
|
|
|
// TestCreateDerefOnError ensures that if a volume create fails, that the plugin is dereferenced
|
|
// Normally 1 volume == 1 reference to a plugin, which prevents a plugin from being removed.
|
|
// If the volume create fails, we should make sure to dereference the plugin.
|
|
func TestCreateDerefOnError(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
d := daemon.New(t, "", dockerdBinary, daemon.Config{})
|
|
d.Start(t)
|
|
defer d.Stop(t)
|
|
|
|
c, err := d.NewClient()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pName := "testderef"
|
|
createPlugin(t, c, pName, "create-error", asVolumeDriver)
|
|
|
|
if err := c.PluginEnable(context.Background(), pName, types.PluginEnableOptions{Timeout: 30}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = c.VolumeCreate(context.Background(), volume.VolumesCreateBody{
|
|
Driver: pName,
|
|
Name: "fake",
|
|
})
|
|
if err == nil {
|
|
t.Fatal("volume create should have failed")
|
|
}
|
|
|
|
if err := c.PluginDisable(context.Background(), pName, types.PluginDisableOptions{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := c.PluginRemove(context.Background(), pName, types.PluginRemoveOptions{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|