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:
parent
64785ff146
commit
bd4fb00fb6
7 changed files with 142 additions and 7 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue