From 96c79a1934dd52d2a6f648e519b5d4ac60ac8ca1 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Wed, 24 Feb 2016 20:45:38 -0500 Subject: [PATCH] Fix panic when plugin responds with null volume In cases where the a plugin responds with both a null or empty volume and a null or empty Err, the daemon would panic. This is because we assumed the idiom if `err` is nil, then `v` must not be but in reality the plugin may return whatever it wants and we want to make sure it doesn't harm the daemon. Signed-off-by: Brian Goff --- ...docker_cli_start_volume_driver_unix_test.go | 18 +++++++++++++++++- volume/drivers/adapter.go | 11 ++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/integration-cli/docker_cli_start_volume_driver_unix_test.go b/integration-cli/docker_cli_start_volume_driver_unix_test.go index d3dff63d9c..e730676fc9 100644 --- a/integration-cli/docker_cli_start_volume_driver_unix_test.go +++ b/integration-cli/docker_cli_start_volume_driver_unix_test.go @@ -60,6 +60,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) { type pluginRequest struct { Name string + Opts map[string]string } type pluginResp struct { @@ -70,6 +71,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) { type vol struct { Name string Mountpoint string + Ninja bool // hack used to trigger an null volume return on `Get` } var volList []vol @@ -107,7 +109,8 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) { send(w, err) return } - volList = append(volList, vol{Name: pr.Name}) + _, isNinja := pr.Opts["ninja"] + volList = append(volList, vol{Name: pr.Name, Ninja: isNinja}) send(w, nil) }) @@ -126,6 +129,10 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) { for _, v := range volList { if v.Name == pr.Name { + if v.Ninja { + send(w, map[string]vol{}) + return + } v.Mountpoint = hostVolumePath(pr.Name) send(w, map[string]vol{"Volume": v}) return @@ -423,3 +430,12 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverWithDaemnRestart(c * c.Assert(mounts, checker.HasLen, 1) c.Assert(mounts[0].Driver, checker.Equals, "test-external-volume-driver") } + +// Ensures that the daemon handles when the plugin responds to a `Get` request with a null volume and a null error. +// Prior the daemon would panic in this scenario. +func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGetEmptyResponse(c *check.C) { + dockerCmd(c, "volume", "create", "-d", "test-external-volume-driver", "--name", "abc", "--opt", "ninja=1") + out, _, err := dockerCmdWithError("volume", "inspect", "abc") + c.Assert(err, checker.NotNil, check.Commentf(out)) + c.Assert(out, checker.Contains, "No such volume") +} diff --git a/volume/drivers/adapter.go b/volume/drivers/adapter.go index e8868c04e6..1468b34344 100644 --- a/volume/drivers/adapter.go +++ b/volume/drivers/adapter.go @@ -1,6 +1,10 @@ package volumedrivers -import "github.com/docker/docker/volume" +import ( + "fmt" + + "github.com/docker/docker/volume" +) type volumeDriverAdapter struct { name string @@ -49,6 +53,11 @@ func (a *volumeDriverAdapter) Get(name string) (volume.Volume, error) { return nil, err } + // plugin may have returned no volume and no error + if v == nil { + return nil, fmt.Errorf("no such volume") + } + return &volumeAdapter{ proxy: a.proxy, name: v.Name,