diff --git a/daemon/inspect.go b/daemon/inspect.go index 4f497327bd..7dc99dcad0 100644 --- a/daemon/inspect.go +++ b/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 } diff --git a/docs/extend/plugins_volume.md b/docs/extend/plugins_volume.md index cb1bebf581..88798497c3 100644 --- a/docs/extend/plugins_volume.md +++ b/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": "" } diff --git a/docs/reference/api/docker_remote_api_v1.24.md b/docs/reference/api/docker_remote_api_v1.24.md index 1ae41d01fb..8f90598075 100644 --- a/docs/reference/api/docker_remote_api_v1.24.md +++ b/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: diff --git a/docs/reference/commandline/volume_inspect.md b/docs/reference/commandline/volume_inspect.md index 8fdd34d93b..7359c2b5a4 100644 --- a/docs/reference/commandline/volume_inspect.md +++ b/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) \ No newline at end of file +* [Understand Data Volumes](../../userguide/containers/dockervolumes.md) diff --git a/integration-cli/docker_cli_start_volume_driver_unix_test.go b/integration-cli/docker_cli_external_volume_driver_unix_test.go similarity index 95% rename from integration-cli/docker_cli_start_volume_driver_unix_test.go rename to integration-cli/docker_cli_external_volume_driver_unix_test.go index 794980f69a..730cf59b34 100644 --- a/integration-cli/docker_cli_start_volume_driver_unix_test.go +++ b/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) { diff --git a/volume/drivers/adapter.go b/volume/drivers/adapter.go index 1377ff3605..fcbf01f5d6 100644 --- a/volume/drivers/adapter.go +++ b/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 +} diff --git a/volume/local/local.go b/volume/local/local.go index 0bca731a29..d582aa5bdb 100644 --- a/volume/local/local.go +++ b/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 +} diff --git a/volume/testutils/testutils.go b/volume/testutils/testutils.go index 653533696a..96d89258d7 100644 --- a/volume/testutils/testutils.go +++ b/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 diff --git a/volume/volume.go b/volume/volume.go index 1abd1ccb35..a440a58f5b 100644 --- a/volume/volume.go +++ b/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