1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Add mounts to docker ps.

- Allow to filter containers by volume with `--filter volume=name` and `filter volume=/dest`.
- Show their names in the list with the custom format `{{ .Mounts }}`.

Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2016-02-03 17:46:01 -05:00
parent 64785ff146
commit bd4fb00fb6
7 changed files with 142 additions and 7 deletions

View file

@ -31,6 +31,7 @@ const (
repositoryHeader = "REPOSITORY" repositoryHeader = "REPOSITORY"
tagHeader = "TAG" tagHeader = "TAG"
digestHeader = "DIGEST" digestHeader = "DIGEST"
mountsHeader = "MOUNTS"
) )
type containerContext struct { type containerContext struct {
@ -142,6 +143,20 @@ func (c *containerContext) Label(name string) string {
return c.c.Labels[name] return c.c.Labels[name]
} }
func (c *containerContext) Mounts() string {
c.addHeader(mountsHeader)
var mounts []string
for _, m := range c.c.Mounts {
name := m.Name
if c.trunc {
name = stringutils.Truncate(name, 15)
}
mounts = append(mounts, name)
}
return strings.Join(mounts, ",")
}
type imageContext struct { type imageContext struct {
baseSubContext baseSubContext
trunc bool trunc bool

View file

@ -9,6 +9,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/container" "github.com/docker/docker/container"
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/volume"
"github.com/docker/engine-api/types" "github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/filters" "github.com/docker/engine-api/types/filters"
networktypes "github.com/docker/engine-api/types/network" networktypes "github.com/docker/engine-api/types/network"
@ -306,6 +307,27 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
return excludeContainer return excludeContainer
} }
if ctx.filters.Include("volume") {
volumesByName := make(map[string]*volume.MountPoint)
for _, m := range container.MountPoints {
volumesByName[m.Name] = m
}
volumeExist := fmt.Errorf("volume mounted in container")
err := ctx.filters.WalkValues("volume", func(value string) error {
if _, exist := container.MountPoints[value]; exist {
return volumeExist
}
if _, exist := volumesByName[value]; exist {
return volumeExist
}
return nil
})
if err != volumeExist {
return excludeContainer
}
}
if ctx.ancestorFilter { if ctx.ancestorFilter {
if len(ctx.images) == 0 { if len(ctx.images) == 0 {
return excludeContainer return excludeContainer
@ -419,6 +441,7 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
newC.SizeRootFs = sizeRootFs newC.SizeRootFs = sizeRootFs
} }
newC.Labels = container.Config.Labels newC.Labels = container.Config.Labels
newC.Mounts = addMountPoints(container)
return newC, nil return newC, nil
} }

View file

@ -116,6 +116,7 @@ This section lists each version from latest to oldest. Each listing includes a
[Docker Remote API v1.23](docker_remote_api_v1.23.md) documentation [Docker Remote API v1.23](docker_remote_api_v1.23.md) documentation
* `GET /containers/json` returns the state of the container, one of `created`, `restarting`, `running`, `paused`, `exited` or `dead`. * `GET /containers/json` returns the state of the container, one of `created`, `restarting`, `running`, `paused`, `exited` or `dead`.
* `GET /containers/json` returns the mount points for the container.
* `GET /networks/(name)` now returns an `Internal` field showing whether the network is internal or not. * `GET /networks/(name)` now returns an `Internal` field showing whether the network is internal or not.

View file

@ -73,7 +73,18 @@ List containers
"MacAddress": "02:42:ac:11:00:02" "MacAddress": "02:42:ac:11:00:02"
} }
} }
},
"Mounts": [
{
"Name": "fac362...80535",
"Source": "/data",
"Destination": "/data",
"Driver": "local",
"Mode": "ro,Z",
"RW": false,
"Propagation": ""
} }
]
}, },
{ {
"Id": "9cd87474be90", "Id": "9cd87474be90",
@ -102,8 +113,8 @@ List containers
"MacAddress": "02:42:ac:11:00:08" "MacAddress": "02:42:ac:11:00:08"
} }
} }
} },
"Mounts": []
}, },
{ {
"Id": "3176a2479c92", "Id": "3176a2479c92",
@ -132,8 +143,8 @@ List containers
"MacAddress": "02:42:ac:11:00:06" "MacAddress": "02:42:ac:11:00:06"
} }
} }
} },
"Mounts": []
}, },
{ {
"Id": "4cb07b47f9fb", "Id": "4cb07b47f9fb",
@ -162,8 +173,8 @@ List containers
"MacAddress": "02:42:ac:11:00:05" "MacAddress": "02:42:ac:11:00:05"
} }
} }
} },
"Mounts": []
} }
] ]
@ -184,6 +195,10 @@ Query Parameters:
- `status=`(`created`|`restarting`|`running`|`paused`|`exited`|`dead`) - `status=`(`created`|`restarting`|`running`|`paused`|`exited`|`dead`)
- `label=key` or `label="key=value"` of a container label - `label=key` or `label="key=value"` of a container label
- `isolation=`(`default`|`process`|`hyperv`) (Windows daemon only) - `isolation=`(`default`|`process`|`hyperv`) (Windows daemon only)
- `ancestor`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
- `before`=(`<container id>` or `<container name>`)
- `since`=(`<container id>` or `<container name>`)
- `volume`=(`<volume name>` or `<mount point destination>`)
Status Codes: Status Codes:

View file

@ -60,6 +60,7 @@ The currently supported filters are:
* before (container's id or name) - filters containers created before given id or name * before (container's id or name) - filters containers created before given id or name
* since (container's id or name) - filters containers created since given id or name * since (container's id or name) - filters containers created since given id or name
* isolation (default|process|hyperv) (Windows daemon only) * isolation (default|process|hyperv) (Windows daemon only)
* volume (volume name or mount point) - filters containers that mount volumes.
#### Label #### Label
@ -193,6 +194,18 @@ with the same containers as in `before` filter:
9c3527ed70ce busybox "top" 10 minutes ago Up 10 minutes desperate_dubinsky 9c3527ed70ce busybox "top" 10 minutes ago Up 10 minutes desperate_dubinsky
4aace5031105 busybox "top" 10 minutes ago Up 10 minutes focused_hamilton 4aace5031105 busybox "top" 10 minutes ago Up 10 minutes focused_hamilton
#### Volume
The `volume` filter shows only containers that mount a specific volume or have a volume mounted in a specific path:
$ docker ps --filter volume=remote-volume --format "table {{.ID}}\t{{.Mounts}}"
CONTAINER ID MOUNTS
9c3527ed70ce remote-volume
$ docker ps --filter volume=/data --format "table {{.ID}}\t{{.Mounts}}"
CONTAINER ID MOUNTS
9c3527ed70ce remote-volume
## Formatting ## Formatting
@ -213,6 +226,7 @@ Placeholder | Description
`.Names` | Container names. `.Names` | Container names.
`.Labels` | All labels assigned to the container. `.Labels` | All labels assigned to the container.
`.Label` | Value of a specific label for this container. For example `{{.Label "com.docker.swarm.cpu"}}` `.Label` | Value of a specific label for this container. For example `{{.Label "com.docker.swarm.cpu"}}`
`.Mounts` | Names of the volumes mounted in this container.
When using the `--format` option, the `ps` command will either output the data exactly as the template When using the `--format` option, the `ps` command will either output the data exactly as the template
declares or, when using the `table` directive, will include column headers as well. declares or, when using the `table` directive, will include column headers as well.

View file

@ -734,3 +734,56 @@ func (s *DockerSuite) TestPsNotShowPortsOfStoppedContainer(c *check.C) {
fields = strings.Fields(lines[1]) fields = strings.Fields(lines[1])
c.Assert(fields[len(fields)-2], checker.Not(checker.Equals), expected, check.Commentf("Should not got %v", expected)) c.Assert(fields[len(fields)-2], checker.Not(checker.Equals), expected, check.Commentf("Should not got %v", expected))
} }
func (s *DockerSuite) TestPsShowMounts(c *check.C) {
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
mp := prefix + slash + "test"
dockerCmd(c, "volume", "create", "--name", "ps-volume-test")
runSleepingContainer(c, "--name=volume-test-1", "--volume", "ps-volume-test:"+mp)
c.Assert(waitRun("volume-test-1"), checker.IsNil)
runSleepingContainer(c, "--name=volume-test-2", "--volume", mp)
c.Assert(waitRun("volume-test-2"), checker.IsNil)
out, _ := dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}")
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
c.Assert(lines, checker.HasLen, 2)
fields := strings.Fields(lines[0])
c.Assert(fields, checker.HasLen, 2)
annonymounsVolumeID := fields[1]
fields = strings.Fields(lines[1])
c.Assert(fields[1], checker.Equals, "ps-volume-test")
// filter by volume name
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=ps-volume-test")
lines = strings.Split(strings.TrimSpace(string(out)), "\n")
c.Assert(lines, checker.HasLen, 1)
fields = strings.Fields(lines[0])
c.Assert(fields[1], checker.Equals, "ps-volume-test")
// empty results filtering by unknown volume
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=this-volume-should-not-exist")
c.Assert(strings.TrimSpace(string(out)), checker.HasLen, 0)
// filter by mount destination
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+mp)
lines = strings.Split(strings.TrimSpace(string(out)), "\n")
c.Assert(lines, checker.HasLen, 2)
fields = strings.Fields(lines[0])
c.Assert(fields[1], checker.Equals, annonymounsVolumeID)
fields = strings.Fields(lines[1])
c.Assert(fields[1], checker.Equals, "ps-volume-test")
// empty results filtering by unknown mount point
out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+prefix+slash+"this-path-was-never-mounted")
c.Assert(strings.TrimSpace(string(out)), checker.HasLen, 0)
}

View file

@ -35,6 +35,7 @@ the running containers.
- before=(<container-name>|<container-id>) - before=(<container-name>|<container-id>)
- since=(<container-name>|<container-id>) - since=(<container-name>|<container-id>)
- ancestor=(<image-name>[:tag]|<image-id>|<image@digest>) - containers created from an image or a descendant. - ancestor=(<image-name>[:tag]|<image-id>|<image@digest>) - containers created from an image or a descendant.
- volume=(<volume-name>|<mount-point-destination>)
**--format**="*TEMPLATE*" **--format**="*TEMPLATE*"
Pretty-print containers using a Go template. Pretty-print containers using a Go template.
@ -50,6 +51,7 @@ the running containers.
.Names - Container names. .Names - Container names.
.Labels - All labels assigned to the container. .Labels - All labels assigned to the container.
.Label - Value of a specific label for this container. For example `{{.Label "com.docker.swarm.cpu"}}` .Label - Value of a specific label for this container. For example `{{.Label "com.docker.swarm.cpu"}}`
.Mounts - Names of the volumes mounted in this container.
**--help** **--help**
Print usage statement Print usage statement
@ -118,6 +120,18 @@ the running containers.
c1d3b0166030 debian c1d3b0166030 debian
41d50ecd2f57 fedora 41d50ecd2f57 fedora
# Display containers with `remote-volume` mounted
$ docker ps --filter volume=remote-volume --format "table {{.ID}}\t{{.Mounts}}"
CONTAINER ID MOUNTS
9c3527ed70ce remote-volume
# Display containers with a volume mounted in `/data`
$ docker ps --filter volume=/data --format "table {{.ID}}\t{{.Mounts}}"
CONTAINER ID MOUNTS
9c3527ed70ce remote-volume
# HISTORY # HISTORY
April 2014, Originally compiled by William Henry (whenry at redhat dot com) April 2014, Originally compiled by William Henry (whenry at redhat dot com)
based on docker.com source material and internal work. based on docker.com source material and internal work.