mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Expose new mount points structs in inspect.
Keep old hashes around for old api version calls. Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
parent
48a01a317c
commit
1c3cb2d31e
14 changed files with 264 additions and 89 deletions
|
@ -1193,8 +1193,8 @@ func (s *Server) getContainersByName(version version.Version, w http.ResponseWri
|
|||
return fmt.Errorf("Missing parameter")
|
||||
}
|
||||
|
||||
if version.LessThan("1.19") {
|
||||
containerJSONRaw, err := s.daemon.ContainerInspectRaw(vars["name"])
|
||||
if version.LessThan("1.20") {
|
||||
containerJSONRaw, err := s.daemon.ContainerInspectPre120(vars["name"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -225,8 +225,6 @@ type ContainerJSONBase struct {
|
|||
ExecDriver string
|
||||
MountLabel string
|
||||
ProcessLabel string
|
||||
Volumes map[string]string
|
||||
VolumesRW map[string]bool
|
||||
AppArmorProfile string
|
||||
ExecIDs []string
|
||||
HostConfig *runconfig.HostConfig
|
||||
|
@ -235,12 +233,15 @@ type ContainerJSONBase struct {
|
|||
|
||||
type ContainerJSON struct {
|
||||
*ContainerJSONBase
|
||||
Mounts []MountPoint
|
||||
Config *runconfig.Config
|
||||
}
|
||||
|
||||
// backcompatibility struct along with ContainerConfig
|
||||
type ContainerJSONRaw struct {
|
||||
type ContainerJSONPre120 struct {
|
||||
*ContainerJSONBase
|
||||
Volumes map[string]string
|
||||
VolumesRW map[string]bool
|
||||
Config *ContainerConfig
|
||||
}
|
||||
|
||||
|
@ -253,3 +254,13 @@ type ContainerConfig struct {
|
|||
CpuShares int64
|
||||
Cpuset string
|
||||
}
|
||||
|
||||
// MountPoint represents a mount point configuration inside the container.
|
||||
type MountPoint struct {
|
||||
Name string `json:",omitempty"`
|
||||
Source string
|
||||
Destination string
|
||||
Driver string `json:",omitempty"`
|
||||
Mode string // this is internally named `Relabel`
|
||||
RW bool
|
||||
}
|
||||
|
|
|
@ -20,10 +20,22 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &types.ContainerJSON{base, container.Config}, nil
|
||||
mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
|
||||
for _, m := range container.MountPoints {
|
||||
mountPoints = append(mountPoints, types.MountPoint{
|
||||
Name: m.Name,
|
||||
Source: m.Path(),
|
||||
Destination: m.Destination,
|
||||
Driver: m.Driver,
|
||||
Mode: m.Relabel,
|
||||
RW: m.RW,
|
||||
})
|
||||
}
|
||||
|
||||
return &types.ContainerJSON{base, mountPoints, container.Config}, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) ContainerInspectRaw(name string) (*types.ContainerJSONRaw, error) {
|
||||
func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONPre120, error) {
|
||||
container, err := daemon.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -37,6 +49,13 @@ func (daemon *Daemon) ContainerInspectRaw(name string) (*types.ContainerJSONRaw,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
volumes := make(map[string]string)
|
||||
volumesRW := make(map[string]bool)
|
||||
for _, m := range container.MountPoints {
|
||||
volumes[m.Destination] = m.Path()
|
||||
volumesRW[m.Destination] = m.RW
|
||||
}
|
||||
|
||||
config := &types.ContainerConfig{
|
||||
container.Config,
|
||||
container.hostConfig.Memory,
|
||||
|
@ -45,7 +64,7 @@ func (daemon *Daemon) ContainerInspectRaw(name string) (*types.ContainerJSONRaw,
|
|||
container.hostConfig.CpusetCpus,
|
||||
}
|
||||
|
||||
return &types.ContainerJSONRaw{base, config}, nil
|
||||
return &types.ContainerJSONPre120{base, volumes, volumesRW, config}, nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) {
|
||||
|
@ -76,14 +95,6 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
|
|||
FinishedAt: container.State.FinishedAt,
|
||||
}
|
||||
|
||||
volumes := make(map[string]string)
|
||||
volumesRW := make(map[string]bool)
|
||||
|
||||
for _, m := range container.MountPoints {
|
||||
volumes[m.Destination] = m.Path()
|
||||
volumesRW[m.Destination] = m.RW
|
||||
}
|
||||
|
||||
contJSONBase := &types.ContainerJSONBase{
|
||||
Id: container.ID,
|
||||
Created: container.Created,
|
||||
|
@ -102,8 +113,6 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
|
|||
ExecDriver: container.ExecDriver,
|
||||
MountLabel: container.MountLabel,
|
||||
ProcessLabel: container.ProcessLabel,
|
||||
Volumes: volumes,
|
||||
VolumesRW: volumesRW,
|
||||
AppArmorProfile: container.AppArmorProfile,
|
||||
ExecIDs: container.GetExecIDs(),
|
||||
HostConfig: &hostConfig,
|
||||
|
|
|
@ -140,9 +140,14 @@ Create a container
|
|||
"com.example.license": "GPL",
|
||||
"com.example.version": "1.0"
|
||||
},
|
||||
"Volumes": {
|
||||
"/tmp": {}
|
||||
},
|
||||
"Mounts": [
|
||||
{
|
||||
"Source": "/data",
|
||||
"Destination": "/data",
|
||||
"Mode": "ro,Z",
|
||||
"RW": false
|
||||
}
|
||||
],
|
||||
"WorkingDir": "",
|
||||
"NetworkDisabled": false,
|
||||
"MacAddress": "12:34:56:78:9a:bc",
|
||||
|
@ -223,8 +228,7 @@ Json Parameters:
|
|||
- **Entrypoint** - Set the entry point for the container as a string or an array
|
||||
of strings.
|
||||
- **Image** - A string specifying the image name to use for the container.
|
||||
- **Volumes** – An object mapping mount point paths (strings) inside the
|
||||
container to empty objects.
|
||||
- **Mounts** - An array of mount points in the container.
|
||||
- **WorkingDir** - A string specifying the working directory for commands to
|
||||
run in.
|
||||
- **NetworkDisabled** - Boolean value, when true disables networking for the
|
||||
|
@ -420,8 +424,14 @@ Return low-level information on the container `id`
|
|||
"Running": false,
|
||||
"StartedAt": "2015-01-06T15:47:32.072697474Z"
|
||||
},
|
||||
"Volumes": {},
|
||||
"VolumesRW": {}
|
||||
"Mounts": [
|
||||
{
|
||||
"Source": "/data",
|
||||
"Destination": "/data",
|
||||
"Mode": "ro,Z",
|
||||
"RW": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Status Codes:
|
||||
|
@ -1694,9 +1704,14 @@ Create a new image from a container's changes
|
|||
"Cmd": [
|
||||
"date"
|
||||
],
|
||||
"Volumes": {
|
||||
"/tmp": {}
|
||||
},
|
||||
"Mounts": [
|
||||
{
|
||||
"Source": "/data",
|
||||
"Destination": "/data",
|
||||
"Mode": "ro,Z",
|
||||
"RW": false
|
||||
}
|
||||
],
|
||||
"Labels": {
|
||||
"key1": "value1",
|
||||
"key2": "value2"
|
||||
|
@ -2082,8 +2097,7 @@ Return low-level information about the `exec` command `id`.
|
|||
"ProcessLabel" : "",
|
||||
"AppArmorProfile" : "",
|
||||
"RestartCount" : 0,
|
||||
"Volumes" : {},
|
||||
"VolumesRW" : {}
|
||||
"Mounts" : [],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -190,7 +190,7 @@ func (s *DockerSuite) TestContainerApiStartVolumeBinds(c *check.C) {
|
|||
c.Assert(err, check.IsNil)
|
||||
c.Assert(status, check.Equals, http.StatusNoContent)
|
||||
|
||||
pth, err := inspectFieldMap(name, "Volumes", "/tmp")
|
||||
pth, err := inspectMountSourceField(name, "/tmp")
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
|
|||
|
||||
dockerCmd(c, "run", "-d", "--name", volName, "-v", volPath, "busybox")
|
||||
|
||||
name := "TestContainerApiStartDupVolumeBinds"
|
||||
name := "TestContainerApiStartVolumesFrom"
|
||||
config := map[string]interface{}{
|
||||
"Image": "busybox",
|
||||
"Volumes": map[string]struct{}{volPath: {}},
|
||||
|
@ -250,11 +250,11 @@ func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
|
|||
c.Assert(err, check.IsNil)
|
||||
c.Assert(status, check.Equals, http.StatusNoContent)
|
||||
|
||||
pth, err := inspectFieldMap(name, "Volumes", volPath)
|
||||
pth, err := inspectMountSourceField(name, volPath)
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
pth2, err := inspectFieldMap(volName, "Volumes", volPath)
|
||||
pth2, err := inspectMountSourceField(volName, volPath)
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
@ -705,7 +705,7 @@ func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
|
|||
func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) {
|
||||
dockerCmd(c, "create", "-v", "/foo", "--name=one", "busybox")
|
||||
|
||||
fooDir, err := inspectFieldMap("one", "Volumes", "/foo")
|
||||
fooDir, err := inspectMountSourceField("one", "/foo")
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
@ -717,7 +717,7 @@ func (s *DockerSuite) TestPostContainerBindNormalVolume(c *check.C) {
|
|||
c.Assert(err, check.IsNil)
|
||||
c.Assert(status, check.Equals, http.StatusNoContent)
|
||||
|
||||
fooDir2, err := inspectFieldMap("two", "Volumes", "/foo")
|
||||
fooDir2, err := inspectMountSourceField("two", "/foo")
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
@ -1467,17 +1467,15 @@ func (s *DockerSuite) TestContainerApiDeleteRemoveVolume(c *check.C) {
|
|||
id := strings.TrimSpace(out)
|
||||
c.Assert(waitRun(id), check.IsNil)
|
||||
|
||||
vol, err := inspectFieldMap(id, "Volumes", "/testvolume")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
_, err = os.Stat(vol)
|
||||
source, err := inspectMountSourceField(id, "/testvolume")
|
||||
_, err = os.Stat(source)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
status, _, err := sockRequest("DELETE", "/containers/"+id+"?v=1&force=1", nil)
|
||||
c.Assert(err, check.IsNil)
|
||||
c.Assert(status, check.Equals, http.StatusNoContent)
|
||||
|
||||
if _, err := os.Stat(vol); !os.IsNotExist(err) {
|
||||
if _, err := os.Stat(source); !os.IsNotExist(err) {
|
||||
c.Fatalf("expected to get ErrNotExist error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
|
@ -12,28 +13,38 @@ func (s *DockerSuite) TestInspectApiContainerResponse(c *check.C) {
|
|||
out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
keysBase := []string{"Id", "State", "Created", "Path", "Args", "Config", "Image", "NetworkSettings",
|
||||
"ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "ExecDriver", "MountLabel", "ProcessLabel", "GraphDriver"}
|
||||
|
||||
cases := []struct {
|
||||
version string
|
||||
keys []string
|
||||
}{
|
||||
{"1.20", append(keysBase, "Mounts")},
|
||||
{"1.19", append(keysBase, "Volumes", "VolumesRW")},
|
||||
}
|
||||
|
||||
for _, cs := range cases {
|
||||
endpoint := fmt.Sprintf("/v%s/containers/%s/json", cs.version, cleanedContainerID)
|
||||
|
||||
endpoint := "/containers/" + cleanedContainerID + "/json"
|
||||
status, body, err := sockRequest("GET", endpoint, nil)
|
||||
c.Assert(status, check.Equals, http.StatusOK)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
var inspectJSON map[string]interface{}
|
||||
if err = json.Unmarshal(body, &inspectJSON); err != nil {
|
||||
c.Fatalf("unable to unmarshal body for latest version: %v", err)
|
||||
c.Fatalf("unable to unmarshal body for version %s: %v", cs.version, err)
|
||||
}
|
||||
|
||||
keys := []string{"State", "Created", "Path", "Args", "Config", "Image", "NetworkSettings", "ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "ExecDriver", "MountLabel", "ProcessLabel", "Volumes", "VolumesRW", "GraphDriver"}
|
||||
|
||||
keys = append(keys, "Id")
|
||||
|
||||
for _, key := range keys {
|
||||
for _, key := range cs.keys {
|
||||
if _, ok := inspectJSON[key]; !ok {
|
||||
c.Fatalf("%s does not exist in response for latest version", key)
|
||||
c.Fatalf("%s does not exist in response for version %s", key, cs.version)
|
||||
}
|
||||
}
|
||||
|
||||
//Issue #6830: type not properly converted to JSON/back
|
||||
if _, ok := inspectJSON["Path"].(bool); ok {
|
||||
c.Fatalf("Path of `true` should not be converted to boolean `true` via JSON marshalling")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -184,7 +184,7 @@ func (s *DockerSuite) TestCreateVolumesCreated(c *check.C) {
|
|||
name := "test_create_volume"
|
||||
dockerCmd(c, "create", "--name", name, "-v", "/foo", "busybox")
|
||||
|
||||
dir, err := inspectFieldMap(name, "Volumes", "/foo")
|
||||
dir, err := inspectMountSourceField(name, "/foo")
|
||||
if err != nil {
|
||||
c.Fatalf("Error getting volume host path: %q", err)
|
||||
}
|
||||
|
|
|
@ -67,23 +67,23 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithVolumesRefs(c *check.C) {
|
|||
if out, err := s.d.Cmd("run", "-d", "--name", "volrestarttest1", "-v", "/foo", "busybox"); err != nil {
|
||||
c.Fatal(err, out)
|
||||
}
|
||||
|
||||
if err := s.d.Restart(); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
if _, err := s.d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox", "top"); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
if out, err := s.d.Cmd("rm", "-fv", "volrestarttest2"); err != nil {
|
||||
c.Fatal(err, out)
|
||||
}
|
||||
v, err := s.d.Cmd("inspect", "--format", "{{ json .Volumes }}", "volrestarttest1")
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
volumes := make(map[string]string)
|
||||
json.Unmarshal([]byte(v), &volumes)
|
||||
if _, err := os.Stat(volumes["/foo"]); err != nil {
|
||||
c.Fatalf("Expected volume to exist: %s - %s", volumes["/foo"], err)
|
||||
|
||||
out, err := s.d.Cmd("inspect", "-f", "{{json .Mounts}}", "volrestarttest1")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
if _, err := inspectMountPointJSON(out, "/foo"); err != nil {
|
||||
c.Fatalf("Expected volume to exist: /foo, error: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
44
integration-cli/docker_cli_inspect_experimental_test.go
Normal file
44
integration-cli/docker_cli_inspect_experimental_test.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
// +build experimental
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
func (s *DockerSuite) TestInspectNamedMountPoint(c *check.C) {
|
||||
dockerCmd(c, "run", "-d", "--name", "test", "-v", "data:/data", "busybox", "cat")
|
||||
|
||||
vol, err := inspectFieldJSON("test", "Mounts")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
var mp []types.MountPoint
|
||||
err = unmarshalJSON([]byte(vol), &mp)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
if len(mp) != 1 {
|
||||
c.Fatalf("Expected 1 mount point, was %v\n", len(mp))
|
||||
}
|
||||
|
||||
m := mp[0]
|
||||
if m.Name != "data" {
|
||||
c.Fatalf("Expected name data, was %s\n", m.Name)
|
||||
}
|
||||
|
||||
if m.Driver != "local" {
|
||||
c.Fatalf("Expected driver local, was %s\n", m.Driver)
|
||||
}
|
||||
|
||||
if m.Source == "" {
|
||||
c.Fatalf("Expected source to not be empty")
|
||||
}
|
||||
|
||||
if m.RW != true {
|
||||
c.Fatalf("Expected rw to be true")
|
||||
}
|
||||
|
||||
if m.Destination != "/data" {
|
||||
c.Fatalf("Expected destination /data, was %s\n", m.Destination)
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
|
@ -18,7 +19,6 @@ func (s *DockerSuite) TestInspectImage(c *check.C) {
|
|||
if id != imageTestID {
|
||||
c.Fatalf("Expected id: %s for image: %s but received id: %s", imageTestID, imageTest, id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectInt64(c *check.C) {
|
||||
|
@ -265,3 +265,44 @@ func (s *DockerSuite) TestInspectContainerGraphDriver(c *check.C) {
|
|||
c.Fatalf("failed to inspect DeviceSize of the image: %s, %v", deviceSize, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestInspectBindMountPoint(c *check.C) {
|
||||
dockerCmd(c, "run", "-d", "--name", "test", "-v", "/data:/data:ro,z", "busybox", "cat")
|
||||
|
||||
vol, err := inspectFieldJSON("test", "Mounts")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
var mp []types.MountPoint
|
||||
err = unmarshalJSON([]byte(vol), &mp)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
if len(mp) != 1 {
|
||||
c.Fatalf("Expected 1 mount point, was %v\n", len(mp))
|
||||
}
|
||||
|
||||
m := mp[0]
|
||||
|
||||
if m.Name != "" {
|
||||
c.Fatal("Expected name to be empty")
|
||||
}
|
||||
|
||||
if m.Driver != "" {
|
||||
c.Fatal("Expected driver to be empty")
|
||||
}
|
||||
|
||||
if m.Source != "/data" {
|
||||
c.Fatalf("Expected source /data, was %s\n", m.Source)
|
||||
}
|
||||
|
||||
if m.Destination != "/data" {
|
||||
c.Fatalf("Expected destination /data, was %s\n", m.Destination)
|
||||
}
|
||||
|
||||
if m.Mode != "ro,z" {
|
||||
c.Fatalf("Expected mode `ro,z`, was %s\n", m.Mode)
|
||||
}
|
||||
|
||||
if m.RW != false {
|
||||
c.Fatalf("Expected rw to be false")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,27 +54,27 @@ func (s *DockerSuite) TestRestartWithVolumes(c *check.C) {
|
|||
out, _ := dockerCmd(c, "run", "-d", "-v", "/test", "busybox", "top")
|
||||
|
||||
cleanedContainerID := strings.TrimSpace(out)
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{ len .Volumes }}", cleanedContainerID)
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{ len .Mounts }}", cleanedContainerID)
|
||||
|
||||
if out = strings.Trim(out, " \n\r"); out != "1" {
|
||||
c.Errorf("expect 1 volume received %s", out)
|
||||
}
|
||||
|
||||
volumes, err := inspectField(cleanedContainerID, "Volumes")
|
||||
source, err := inspectMountSourceField(cleanedContainerID, "/test")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
dockerCmd(c, "restart", cleanedContainerID)
|
||||
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{ len .Volumes }}", cleanedContainerID)
|
||||
out, _ = dockerCmd(c, "inspect", "--format", "{{ len .Mounts }}", cleanedContainerID)
|
||||
if out = strings.Trim(out, " \n\r"); out != "1" {
|
||||
c.Errorf("expect 1 volume after restart received %s", out)
|
||||
}
|
||||
|
||||
volumesAfterRestart, err := inspectField(cleanedContainerID, "Volumes")
|
||||
sourceAfterRestart, err := inspectMountSourceField(cleanedContainerID, "/test")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
if volumes != volumesAfterRestart {
|
||||
c.Errorf("expected volume path: %s Actual path: %s", volumes, volumesAfterRestart)
|
||||
if source != sourceAfterRestart {
|
||||
c.Errorf("expected volume path: %s Actual path: %s", source, sourceAfterRestart)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2302,24 +2302,23 @@ func (s *DockerSuite) TestRunVolumesCleanPaths(c *check.C) {
|
|||
c.Fatal(err, out)
|
||||
}
|
||||
|
||||
out, err := inspectFieldMap("dark_helmet", "Volumes", "/foo/")
|
||||
c.Assert(err, check.IsNil)
|
||||
if out != "" {
|
||||
out, err := inspectMountSourceField("dark_helmet", "/foo/")
|
||||
if err != mountNotFound {
|
||||
c.Fatalf("Found unexpected volume entry for '/foo/' in volumes\n%q", out)
|
||||
}
|
||||
|
||||
out, err = inspectFieldMap("dark_helmet", "Volumes", "/foo")
|
||||
out, err = inspectMountSourceField("dark_helmet", "/foo")
|
||||
c.Assert(err, check.IsNil)
|
||||
if !strings.Contains(out, volumesConfigPath) {
|
||||
c.Fatalf("Volume was not defined for /foo\n%q", out)
|
||||
}
|
||||
|
||||
out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar/")
|
||||
c.Assert(err, check.IsNil)
|
||||
if out != "" {
|
||||
out, err = inspectMountSourceField("dark_helmet", "/bar/")
|
||||
if err != mountNotFound {
|
||||
c.Fatalf("Found unexpected volume entry for '/bar/' in volumes\n%q", out)
|
||||
}
|
||||
out, err = inspectFieldMap("dark_helmet", "Volumes", "/bar")
|
||||
|
||||
out, err = inspectMountSourceField("dark_helmet", "/bar")
|
||||
c.Assert(err, check.IsNil)
|
||||
if !strings.Contains(out, volumesConfigPath) {
|
||||
c.Fatalf("Volume was not defined for /bar\n%q", out)
|
||||
|
@ -3107,14 +3106,15 @@ func (s *DockerSuite) TestVolumeFromMixedRWOptions(c *check.C) {
|
|||
dockerCmd(c, "run", "--volumes-from", "parent:ro", "--name", "test-volumes-1", "busybox", "true")
|
||||
dockerCmd(c, "run", "--volumes-from", "parent:rw", "--name", "test-volumes-2", "busybox", "true")
|
||||
|
||||
testRO, err := inspectFieldMap("test-volumes-1", ".VolumesRW", "/test")
|
||||
mRO, err := inspectMountPoint("test-volumes-1", "/test")
|
||||
c.Assert(err, check.IsNil)
|
||||
if testRO != "false" {
|
||||
if mRO.RW {
|
||||
c.Fatalf("Expected RO volume was RW")
|
||||
}
|
||||
testRW, err := inspectFieldMap("test-volumes-2", ".VolumesRW", "/test")
|
||||
|
||||
mRW, err := inspectMountPoint("test-volumes-2", "/test")
|
||||
c.Assert(err, check.IsNil)
|
||||
if testRW != "true" {
|
||||
if !mRW.RW {
|
||||
c.Fatalf("Expected RW volume was RO")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
|
@ -874,6 +875,46 @@ func inspectFieldMap(name, path, field string) (string, error) {
|
|||
return inspectFilter(name, fmt.Sprintf("index .%s %q", path, field))
|
||||
}
|
||||
|
||||
func inspectMountSourceField(name, destination string) (string, error) {
|
||||
m, err := inspectMountPoint(name, destination)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return m.Source, nil
|
||||
}
|
||||
|
||||
func inspectMountPoint(name, destination string) (types.MountPoint, error) {
|
||||
out, err := inspectFieldJSON(name, "Mounts")
|
||||
if err != nil {
|
||||
return types.MountPoint{}, err
|
||||
}
|
||||
|
||||
return inspectMountPointJSON(out, destination)
|
||||
}
|
||||
|
||||
var mountNotFound = errors.New("mount point not found")
|
||||
|
||||
func inspectMountPointJSON(j, destination string) (types.MountPoint, error) {
|
||||
var mp []types.MountPoint
|
||||
if err := unmarshalJSON([]byte(j), &mp); err != nil {
|
||||
return types.MountPoint{}, err
|
||||
}
|
||||
|
||||
var m *types.MountPoint
|
||||
for _, c := range mp {
|
||||
if c.Destination == destination {
|
||||
m = &c
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if m == nil {
|
||||
return types.MountPoint{}, mountNotFound
|
||||
}
|
||||
|
||||
return *m, nil
|
||||
}
|
||||
|
||||
func getIDByName(name string) (string, error) {
|
||||
return inspectField(name, "Id")
|
||||
}
|
||||
|
|
|
@ -95,8 +95,14 @@ To get information on a container use its ID or instance name:
|
|||
"ExecDriver": "native-0.2",
|
||||
"MountLabel": "",
|
||||
"ProcessLabel": "",
|
||||
"Volumes": {},
|
||||
"VolumesRW": {},
|
||||
"Mounts": [
|
||||
{
|
||||
"Source": "/data",
|
||||
"Destination": "/data",
|
||||
"Mode": "ro,Z",
|
||||
"RW": false
|
||||
}
|
||||
],
|
||||
"AppArmorProfile": "",
|
||||
"ExecIDs": null,
|
||||
"HostConfig": {
|
||||
|
|
Loading…
Reference in a new issue