Browse Source

Allow volume drivers to provide a `Status` field

The `Status` field is a `map[string]interface{}` which allows the driver to pass
back low-level details about the underlying volume.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Brian Goff 9 years ago
parent
commit
36a1c56cf5

+ 1 - 0
daemon/inspect.go

@@ -206,6 +206,7 @@ func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) {
 	}
 	apiV := volumeToAPIType(v)
 	apiV.Mountpoint = v.Path()
+	apiV.Status = v.Status()
 	return apiV, nil
 }
 

+ 16 - 0
docs/extend/plugins_volume.md

@@ -15,6 +15,21 @@ external storage systems, such as Amazon EBS, and enable data volumes to persist
 beyond the lifetime of a single Engine host. See the [plugin
 documentation](plugins.md) for more information.
 
+## Changelog
+
+### 1.12.0
+
+- Add `Status` field to `VolumeDriver.Get` response ([#21006](https://github.com/docker/docker/pull/21006#))
+
+### 1.10.0
+
+- Add `VolumeDriver.Get` which gets the details about the volume ([#16534](https://github.com/docker/docker/pull/16534))
+- Add `VolumeDriver.List` which lists all volumes owned by the driver ([#16534](https://github.com/docker/docker/pull/16534))
+
+### 1.8.0
+
+- Initial support for volume driver plugins ([#14659](https://github.com/docker/docker/pull/14659))
+
 ## Command-line changes
 
 A volume plugin makes use of the `-v`and `--volume-driver` flag on the `docker run` command.  The `-v` flag accepts a volume name and the `--volume-driver` flag a driver type, for example:
@@ -183,6 +198,7 @@ Get the volume info.
   "Volume": {
     "Name": "volume_name",
     "Mountpoint": "/path/to/directory/on/host",
+    "Status": {}
   },
   "Err": ""
 }

+ 2 - 1
docs/reference/api/docker_remote_api_v1.24.md

@@ -2792,7 +2792,8 @@ Create a volume
     {
       "Name": "tardis",
       "Driver": "local",
-      "Mountpoint": "/var/lib/docker/volumes/tardis"
+      "Mountpoint": "/var/lib/docker/volumes/tardis",
+      "Status": null
     }
 
 Status Codes:

+ 3 - 2
docs/reference/commandline/volume_inspect.md

@@ -32,7 +32,8 @@ Example output:
       {
           "Name": "85bffb0677236974f93955d8ecc4df55ef5070117b0e53333cc1b443777be24d",
           "Driver": "local",
-          "Mountpoint": "/var/lib/docker/volumes/85bffb0677236974f93955d8ecc4df55ef5070117b0e53333cc1b443777be24d/_data"
+          "Mountpoint": "/var/lib/docker/volumes/85bffb0677236974f93955d8ecc4df55ef5070117b0e53333cc1b443777be24d/_data",
+          "Status": null
       }
     ]
 
@@ -44,4 +45,4 @@ Example output:
 * [volume create](volume_create.md)
 * [volume ls](volume_ls.md)
 * [volume rm](volume_rm.md)
-* [Understand Data Volumes](../../userguide/containers/dockervolumes.md)
+* [Understand Data Volumes](../../userguide/containers/dockervolumes.md)

+ 17 - 1
integration-cli/docker_cli_start_volume_driver_unix_test.go → integration-cli/docker_cli_external_volume_driver_unix_test.go

@@ -72,6 +72,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
 		Name       string
 		Mountpoint string
 		Ninja      bool // hack used to trigger an null volume return on `Get`
+		Status     map[string]interface{}
 	}
 	var volList []vol
 
@@ -110,7 +111,8 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
 			return
 		}
 		_, isNinja := pr.Opts["ninja"]
-		volList = append(volList, vol{Name: pr.Name, Ninja: isNinja})
+		status := map[string]interface{}{"Hello": "world"}
+		volList = append(volList, vol{Name: pr.Name, Ninja: isNinja, Status: status})
 		send(w, nil)
 	})
 
@@ -140,6 +142,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
 					send(w, map[string]vol{})
 					return
 				}
+
 				v.Mountpoint = hostVolumePath(pr.Name)
 				send(w, map[string]vol{"Volume": v})
 				return
@@ -419,6 +422,19 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverGet(c *check.C) {
 	c.Assert(err, check.NotNil, check.Commentf(out))
 	c.Assert(s.ec.gets, check.Equals, 1)
 	c.Assert(out, checker.Contains, "No such volume")
+
+	dockerCmd(c, "volume", "create", "--name", "test", "-d", "test-external-volume-driver")
+	out, _ = dockerCmd(c, "volume", "inspect", "test")
+
+	type vol struct {
+		Status map[string]string
+	}
+	var st []vol
+
+	c.Assert(json.Unmarshal([]byte(out), &st), checker.IsNil)
+	c.Assert(st, checker.HasLen, 1)
+	c.Assert(st[0].Status, checker.HasLen, 1, check.Commentf("%v", st[0]))
+	c.Assert(st[0].Status["Hello"], checker.Equals, "world", check.Commentf("%v", st[0].Status))
 }
 
 func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverWithDaemnRestart(c *check.C) {

+ 11 - 0
volume/drivers/adapter.go

@@ -64,6 +64,7 @@ func (a *volumeDriverAdapter) Get(name string) (volume.Volume, error) {
 		name:       v.Name,
 		driverName: a.Name(),
 		eMount:     v.Mountpoint,
+		status:     v.Status,
 	}, nil
 }
 
@@ -72,11 +73,13 @@ type volumeAdapter struct {
 	name       string
 	driverName string
 	eMount     string // ephemeral host volume path
+	status     map[string]interface{}
 }
 
 type proxyVolume struct {
 	Name       string
 	Mountpoint string
+	Status     map[string]interface{}
 }
 
 func (a *volumeAdapter) Name() string {
@@ -111,3 +114,11 @@ func (a *volumeAdapter) Unmount() error {
 	}
 	return err
 }
+
+func (a *volumeAdapter) Status() map[string]interface{} {
+	out := make(map[string]interface{}, len(a.status))
+	for k, v := range a.status {
+		out[k] = v
+	}
+	return out
+}

+ 4 - 0
volume/local/local.go

@@ -328,3 +328,7 @@ func validateOpts(opts map[string]string) error {
 	}
 	return nil
 }
+
+func (v *localVolume) Status() map[string]interface{} {
+	return nil
+}

+ 6 - 0
volume/testutils/testutils.go

@@ -24,6 +24,9 @@ func (NoopVolume) Mount() (string, error) { return "noop", nil }
 // Unmount unmounts the volume from the container
 func (NoopVolume) Unmount() error { return nil }
 
+// Status proivdes low-level details about the volume
+func (NoopVolume) Status() map[string]interface{} { return nil }
+
 // FakeVolume is a fake volume with a random name
 type FakeVolume struct {
 	name       string
@@ -50,6 +53,9 @@ func (FakeVolume) Mount() (string, error) { return "fake", nil }
 // Unmount unmounts the volume from the container
 func (FakeVolume) Unmount() error { return nil }
 
+// Status proivdes low-level details about the volume
+func (FakeVolume) Status() map[string]interface{} { return nil }
+
 // FakeDriver is a driver that generates fake volumes
 type FakeDriver struct {
 	name string

+ 2 - 0
volume/volume.go

@@ -41,6 +41,8 @@ type Volume interface {
 	Mount() (string, error)
 	// Unmount unmounts the volume when it is no longer in use.
 	Unmount() error
+	// Status returns low-level status information about a volume
+	Status() map[string]interface{}
 }
 
 // MountPoint is the intersection point between a volume and a container. It