Przeglądaj źródła

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 <cpuguy83@gmail.com>
(cherry picked from commit 96c79a1934dd52d2a6f648e519b5d4ac60ac8ca1)
Brian Goff 9 lat temu
rodzic
commit
d0165c4085

+ 17 - 1
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")
+}

+ 7 - 0
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,