From d0165c4085e3f2823173bad2fa4fedfeadf6dfe6 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 (cherry picked from commit 96c79a1934dd52d2a6f648e519b5d4ac60ac8ca1) --- ...docker_cli_start_volume_driver_unix_test.go | 18 +++++++++++++++++- volume/drivers/adapter.go | 7 +++++++ 2 files changed, 24 insertions(+), 1 deletion(-) 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 30c540428b..6ee53b4b5b 100644 --- a/integration-cli/docker_cli_start_volume_driver_unix_test.go +++ b/integration-cli/docker_cli_start_volume_driver_unix_test.go @@ -59,6 +59,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) { type pluginRequest struct { Name string + Opts map[string]string } type pluginResp struct { @@ -69,6 +70,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 @@ -106,7 +108,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) }) @@ -125,6 +128,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 @@ -411,3 +418,12 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGet(c *check.C) { c.Assert(s.ec.gets, check.Equals, 1) c.Assert(out, checker.Contains, "No such volume") } + +// 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 064dbffe36..0ebab74519 100644 --- a/volume/drivers/adapter.go +++ b/volume/drivers/adapter.go @@ -1,6 +1,8 @@ package volumedrivers import ( + "fmt" + "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/volume" ) @@ -70,6 +72,11 @@ func (a *volumeDriverAdapter) Get(name string) (volume.Volume, error) { return a.Create(name, nil) } + // 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,