1
0
mirror of https://github.com/docker/docs.git synced 2026-11-11 04:02:07 +03:00

Merge pull request #1248 from dnephin/fix_label_ignored_by_ps

Support filtering images by labels
This commit is contained in:
Andrea Luzzardi
2015-10-02 13:49:19 -07:00
11 changed files with 80 additions and 15 deletions

2
Godeps/Godeps.json generated
View File

@@ -104,7 +104,7 @@
},
{
"ImportPath": "github.com/samalba/dockerclient",
"Rev": "cfb489c624b635251a93e74e1e90eb0959c5367f"
"Rev": "73edd1c3a9d280bcec6a22a12fc90c1a46558b4e"
},
{
"ImportPath": "github.com/samuel/go-zookeeper/zk",

View File

@@ -272,7 +272,9 @@ type RespContainersCreate struct {
type Image struct {
Created int64
Id string
Labels map[string]string
ParentId string
RepoDigests []string
RepoTags []string
Size int64
VirtualSize int64

View File

@@ -28,7 +28,7 @@ const APIVERSION = "1.16"
func getInfo(c *context, w http.ResponseWriter, r *http.Request) {
info := dockerclient.Info{
Containers: int64(len(c.cluster.Containers())),
Images: int64(len(c.cluster.Images(false))),
Images: int64(len(c.cluster.Images(false, nil))),
DriverStatus: c.statusHandler.Status(),
NEventsListener: int64(c.eventsHandler.Size()),
Debug: c.debug,
@@ -78,7 +78,7 @@ func getImages(c *context, w http.ResponseWriter, r *http.Request) {
// Create a map of engine address to the list of images it holds.
engineImages := make(map[string][]*cluster.Image)
for _, image := range c.cluster.Images(true) {
for _, image := range c.cluster.Images(true, nil) {
engineImages[image.Engine.Addr] = append(engineImages[image.Engine.Addr], image)
}
@@ -122,11 +122,12 @@ func getImagesJSON(c *context, w http.ResponseWriter, r *http.Request) {
return
}
// TODO: apply node filter in engine?
accepteds, _ := filters["node"]
// this struct helps grouping images
// but still keeps their Engine infos as an array.
groupImages := make(map[string]dockerclient.Image)
for _, image := range c.cluster.Images(all) {
for _, image := range c.cluster.Images(all, filters) {
if len(accepteds) != 0 {
found := false
for _, accepted := range accepteds {
@@ -720,7 +721,7 @@ func proxyImage(c *context, w http.ResponseWriter, r *http.Request) {
func proxyImageTagOptional(c *context, w http.ResponseWriter, r *http.Request) {
name := mux.Vars(r)["name"]
for _, image := range c.cluster.Images(true) {
for _, image := range c.cluster.Images(true, nil) {
if len(strings.SplitN(name, ":", 2)) == 2 && image.Match(name, true) ||
len(strings.SplitN(name, ":", 2)) == 1 && image.Match(name, false) {
proxy(c.tlsConfig, image.Engine.Addr, w, r)

View File

@@ -3,6 +3,7 @@ package cluster
import (
"io"
dockerfilters "github.com/docker/docker/pkg/parsers/filters"
"github.com/samalba/dockerclient"
)
@@ -15,7 +16,7 @@ type Cluster interface {
RemoveContainer(container *Container, force, volumes bool) error
// Return all images
Images(all bool) []*Image
Images(all bool, filters dockerfilters.Args) []*Image
// Return one image matching `IDOrName`
Image(IDOrName string) *Image

View File

@@ -12,6 +12,7 @@ import (
"time"
log "github.com/Sirupsen/logrus"
dockerfilters "github.com/docker/docker/pkg/parsers/filters"
"github.com/docker/docker/pkg/version"
"github.com/samalba/dockerclient"
"github.com/samalba/dockerclient/nopclient"
@@ -558,15 +559,28 @@ func (e *Engine) Containers() Containers {
}
// Images returns all the images in the engine
func (e *Engine) Images(all bool) []*Image {
func (e *Engine) Images(all bool, filters dockerfilters.Args) []*Image {
e.RLock()
includeAll := func(image *Image) bool {
// TODO: this is wrong if RepoTags == []
return all || (len(image.RepoTags) != 0 && image.RepoTags[0] != "<none>:<none>")
}
includeFilter := func(image *Image) bool {
if filters == nil {
return true
}
return filters.MatchKVList("label", image.Labels)
}
images := make([]*Image, 0, len(e.images))
for _, image := range e.images {
if all || (!all && len(image.RepoTags) != 0 && image.RepoTags[0] != "<none>:<none>") {
if includeAll(image) && includeFilter(image) {
images = append(images, image)
}
}
// TODO: shouldn't this be defered immediately after locking?
e.RUnlock()
return images
}

View File

@@ -6,6 +6,7 @@ import (
"math"
"testing"
dockerfilters "github.com/docker/docker/pkg/parsers/filters"
"github.com/samalba/dockerclient"
"github.com/samalba/dockerclient/mockclient"
"github.com/samalba/dockerclient/nopclient"
@@ -217,6 +218,35 @@ func TestCreateContainer(t *testing.T) {
assert.Len(t, engine.Containers(), 2)
}
func TestImages(t *testing.T) {
engine := NewEngine("test", 0)
engine.images = []*Image{
{dockerclient.Image{Id: "a"}, engine},
{dockerclient.Image{Id: "b"}, engine},
{dockerclient.Image{Id: "c"}, engine},
}
result := engine.Images(true, nil)
assert.Equal(t, len(result), 3)
}
func TestImagesWithFilter(t *testing.T) {
engine := NewEngine("test", 0)
engine.images = []*Image{
{dockerclient.Image{Id: "a"}, engine},
{dockerclient.Image{
Id: "b",
Labels: map[string]string{"com.example.project": "bar"},
}, engine},
{dockerclient.Image{Id: "c"}, engine},
}
filters := dockerfilters.Args{"label": {"com.example.project=bar"}}
result := engine.Images(true, filters)
assert.Equal(t, len(result), 1)
assert.Equal(t, result[0].Id, "b")
}
func TestTotalMemory(t *testing.T) {
engine := NewEngine("test", 0.05)
engine.Memory = 1024

View File

@@ -12,6 +12,7 @@ import (
"time"
log "github.com/Sirupsen/logrus"
dockerfilters "github.com/docker/docker/pkg/parsers/filters"
"github.com/docker/swarm/cluster"
"github.com/docker/swarm/cluster/mesos/queue"
"github.com/docker/swarm/scheduler"
@@ -190,13 +191,13 @@ func (c *Cluster) RemoveContainer(container *cluster.Container, force, volumes b
}
// Images returns all the images in the cluster.
func (c *Cluster) Images(all bool) []*cluster.Image {
func (c *Cluster) Images(all bool, filters dockerfilters.Args) []*cluster.Image {
c.RLock()
defer c.RUnlock()
out := []*cluster.Image{}
for _, s := range c.slaves {
out = append(out, s.engine.Images(all)...)
out = append(out, s.engine.Images(all, filters)...)
}
return out

View File

@@ -10,6 +10,7 @@ import (
"sync"
log "github.com/Sirupsen/logrus"
dockerfilters "github.com/docker/docker/pkg/parsers/filters"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/units"
"github.com/docker/swarm/cluster"
@@ -237,13 +238,13 @@ func (c *Cluster) monitorDiscovery(ch <-chan discovery.Entries, errCh <-chan err
}
// Images returns all the images in the cluster.
func (c *Cluster) Images(all bool) []*cluster.Image {
func (c *Cluster) Images(all bool, filters dockerfilters.Args) []*cluster.Image {
c.RLock()
defer c.RUnlock()
out := []*cluster.Image{}
for _, e := range c.engines {
out = append(out, e.Images(all)...)
out = append(out, e.Images(all, filters)...)
}
return out
@@ -276,7 +277,7 @@ func (c *Cluster) RemoveImages(name string, force bool) ([]*dockerclient.ImageDe
errs := []string{}
var err error
for _, e := range c.engines {
for _, image := range e.Images(true) {
for _, image := range e.Images(true, nil) {
if image.Match(name, true) {
content, err := image.Engine.RemoveImage(image, name, force)
if err != nil {
@@ -698,7 +699,7 @@ func (c *Cluster) TagImage(IDOrName string, repo string, tag string, force bool)
var err error
found := false
for _, e := range c.engines {
for _, image := range e.Images(true) {
for _, image := range e.Images(true, nil) {
if image.Match(IDOrName, true) {
found = true
err := image.Engine.TagImage(IDOrName, repo, tag, force)

View File

@@ -34,7 +34,7 @@ func NewNode(e *cluster.Engine) *Node {
Name: e.Name,
Labels: e.Labels,
Containers: e.Containers(),
Images: e.Images(true),
Images: e.Images(true, nil),
UsedMemory: e.UsedMemory(),
UsedCpus: e.UsedCpus(),
TotalMemory: e.TotalMemory(),

View File

@@ -43,3 +43,16 @@ function teardown() {
run docker_swarm images -a
[ "${#lines[@]}" -ge 3 ]
}
@test "docker images -f label" {
start_docker_with_busybox 2
swarm_manage
docker_swarm build -t image-with-labels $TESTDATA/imagelabel
run docker_swarm images \
--filter label=com.docker.swarm.test.integration.images=labeltest
[ "$status" -eq 0 ]
[ "${#lines[@]}" -eq 2 ]
[[ "${lines[1]}" == *"image-with-labels"* ]]
}

View File

@@ -0,0 +1,2 @@
FROM scratch
LABEL com.docker.swarm.test.integration.images=labeltest