Skip to content

Commit abb5e9a

Browse files
Set labels on container create
Signed-off-by: Darren Shepherd <darren@rancher.com>
1 parent cdfdfbf commit abb5e9a

File tree

8 files changed

+264
-11
lines changed

8 files changed

+264
-11
lines changed

daemon/list.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
9090
return nil
9191
}
9292

93+
if !psFilters.MatchKVList("label", container.Config.Labels) {
94+
return nil
95+
}
96+
9397
if before != "" && !foundBefore {
9498
if container.ID == beforeCont.ID {
9599
foundBefore = true
@@ -157,6 +161,7 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
157161
out.SetInt64("SizeRw", sizeRw)
158162
out.SetInt64("SizeRootFs", sizeRootFs)
159163
}
164+
out.SetJson("Labels", container.Config.Labels)
160165
outs.Add(out)
161166
return nil
162167
}

graph/list.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ import (
1111
"github.com/docker/docker/pkg/parsers/filters"
1212
)
1313

14-
var acceptedImageFilterTags = map[string]struct{}{"dangling": {}}
14+
var acceptedImageFilterTags = map[string]struct{}{
15+
"dangling": {},
16+
"label": {},
17+
}
1518

1619
func (s *TagStore) CmdImages(job *engine.Job) engine.Status {
1720
var (
1821
allImages map[string]*image.Image
1922
err error
2023
filt_tagged = true
24+
filt_label = false
2125
)
2226

2327
imageFilters, err := filters.FromParam(job.Getenv("filters"))
@@ -38,6 +42,8 @@ func (s *TagStore) CmdImages(job *engine.Job) engine.Status {
3842
}
3943
}
4044

45+
_, filt_label = imageFilters["label"]
46+
4147
if job.GetenvBool("all") && filt_tagged {
4248
allImages, err = s.graph.Map()
4349
} else {
@@ -68,6 +74,9 @@ func (s *TagStore) CmdImages(job *engine.Job) engine.Status {
6874
} else {
6975
// get the boolean list for if only the untagged images are requested
7076
delete(allImages, id)
77+
if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) {
78+
continue
79+
}
7180
if filt_tagged {
7281
out := &engine.Env{}
7382
out.SetJson("ParentId", image.Parent)
@@ -76,6 +85,7 @@ func (s *TagStore) CmdImages(job *engine.Job) engine.Status {
7685
out.SetInt64("Created", image.Created.Unix())
7786
out.SetInt64("Size", image.Size)
7887
out.SetInt64("VirtualSize", image.GetParentsSize(0)+image.Size)
88+
out.SetJson("Labels", image.ContainerConfig.Labels)
7989
lookup[id] = out
8090
}
8191
}
@@ -90,15 +100,19 @@ func (s *TagStore) CmdImages(job *engine.Job) engine.Status {
90100
}
91101

92102
// Display images which aren't part of a repository/tag
93-
if job.Getenv("filter") == "" {
103+
if job.Getenv("filter") == "" || filt_label {
94104
for _, image := range allImages {
105+
if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) {
106+
continue
107+
}
95108
out := &engine.Env{}
96109
out.SetJson("ParentId", image.Parent)
97110
out.SetList("RepoTags", []string{"<none>:<none>"})
98111
out.SetJson("Id", image.ID)
99112
out.SetInt64("Created", image.Created.Unix())
100113
out.SetInt64("Size", image.Size)
101114
out.SetInt64("VirtualSize", image.GetParentsSize(0)+image.Size)
115+
out.SetJson("Labels", image.ContainerConfig.Labels)
102116
outs.Add(out)
103117
}
104118
}

integration-cli/docker_cli_create_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"os"
66
"os/exec"
7+
"reflect"
78
"testing"
89
"time"
910

@@ -249,3 +250,57 @@ func TestCreateVolumesCreated(t *testing.T) {
249250

250251
logDone("create - volumes are created")
251252
}
253+
254+
func TestCreateLabels(t *testing.T) {
255+
name := "test_create_labels"
256+
expected := map[string]string{"k1": "v1", "k2": "v2"}
257+
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "--name", name, "-l", "k1=v1", "--label", "k2=v2", "busybox")); err != nil {
258+
t.Fatal(out, err)
259+
}
260+
261+
actual := make(map[string]string)
262+
err := inspectFieldAndMarshall(name, "Config.Labels", &actual)
263+
if err != nil {
264+
t.Fatal(err)
265+
}
266+
267+
if !reflect.DeepEqual(expected, actual) {
268+
t.Fatalf("Expected %s got %s", expected, actual)
269+
}
270+
271+
deleteAllContainers()
272+
273+
logDone("create - labels")
274+
}
275+
276+
func TestCreateLabelFromImage(t *testing.T) {
277+
imageName := "testcreatebuildlabel"
278+
defer deleteImages(imageName)
279+
_, err := buildImage(imageName,
280+
`FROM busybox
281+
LABEL k1=v1 k2=v2`,
282+
true)
283+
if err != nil {
284+
t.Fatal(err)
285+
}
286+
287+
name := "test_create_labels_from_image"
288+
expected := map[string]string{"k2": "x", "k3": "v3", "k1": "v1"}
289+
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "create", "--name", name, "-l", "k2=x", "--label", "k3=v3", imageName)); err != nil {
290+
t.Fatal(out, err)
291+
}
292+
293+
actual := make(map[string]string)
294+
err = inspectFieldAndMarshall(name, "Config.Labels", &actual)
295+
if err != nil {
296+
t.Fatal(err)
297+
}
298+
299+
if !reflect.DeepEqual(expected, actual) {
300+
t.Fatalf("Expected %s got %s", expected, actual)
301+
}
302+
303+
deleteAllContainers()
304+
305+
logDone("create - labels from image")
306+
}

integration-cli/docker_cli_images_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,60 @@ func TestImagesErrorWithInvalidFilterNameTest(t *testing.T) {
7777
logDone("images - invalid filter name check working")
7878
}
7979

80+
func TestImagesFilterLabel(t *testing.T) {
81+
imageName1 := "images_filter_test1"
82+
imageName2 := "images_filter_test2"
83+
imageName3 := "images_filter_test3"
84+
defer deleteAllContainers()
85+
defer deleteImages(imageName1)
86+
defer deleteImages(imageName2)
87+
defer deleteImages(imageName3)
88+
image1ID, err := buildImage(imageName1,
89+
`FROM scratch
90+
LABEL match me`, true)
91+
if err != nil {
92+
t.Fatal(err)
93+
}
94+
95+
image2ID, err := buildImage(imageName2,
96+
`FROM scratch
97+
LABEL match="me too"`, true)
98+
if err != nil {
99+
t.Fatal(err)
100+
}
101+
102+
image3ID, err := buildImage(imageName3,
103+
`FROM scratch
104+
LABEL nomatch me`, true)
105+
if err != nil {
106+
t.Fatal(err)
107+
}
108+
109+
cmd := exec.Command(dockerBinary, "images", "--no-trunc", "-q", "-f", "label=match")
110+
out, _, err := runCommandWithOutput(cmd)
111+
if err != nil {
112+
t.Fatal(out, err)
113+
}
114+
out = strings.TrimSpace(out)
115+
116+
if (!strings.Contains(out, image1ID) && !strings.Contains(out, image2ID)) || strings.Contains(out, image3ID) {
117+
t.Fatalf("Expected ids %s,%s got %s", image1ID, image2ID, out)
118+
}
119+
120+
cmd = exec.Command(dockerBinary, "images", "--no-trunc", "-q", "-f", "label=match=me too")
121+
out, _, err = runCommandWithOutput(cmd)
122+
if err != nil {
123+
t.Fatal(out, err)
124+
}
125+
out = strings.TrimSpace(out)
126+
127+
if out != image2ID {
128+
t.Fatalf("Expected %s got %s", image2ID, out)
129+
}
130+
131+
logDone("images - filter label")
132+
}
133+
80134
func TestImagesFilterWhiteSpaceTrimmingAndLowerCasingWorking(t *testing.T) {
81135
imageName := "images_filter_test"
82136
defer deleteAllContainers()

integration-cli/docker_cli_ps_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,54 @@ func TestPsListContainersFilterName(t *testing.T) {
412412
logDone("ps - test ps filter name")
413413
}
414414

415+
func TestPsListContainersFilterLabel(t *testing.T) {
416+
// start container
417+
runCmd := exec.Command(dockerBinary, "run", "-d", "-l", "match=me", "busybox")
418+
out, _, err := runCommandWithOutput(runCmd)
419+
if err != nil {
420+
t.Fatal(out, err)
421+
}
422+
firstID := stripTrailingCharacters(out)
423+
424+
// start another container
425+
runCmd = exec.Command(dockerBinary, "run", "-d", "-l", "match=me too", "busybox")
426+
if out, _, err = runCommandWithOutput(runCmd); err != nil {
427+
t.Fatal(out, err)
428+
}
429+
secondID := stripTrailingCharacters(out)
430+
431+
// start third container
432+
runCmd = exec.Command(dockerBinary, "run", "-d", "-l", "nomatch=me", "busybox")
433+
if out, _, err = runCommandWithOutput(runCmd); err != nil {
434+
t.Fatal(out, err)
435+
}
436+
thirdID := stripTrailingCharacters(out)
437+
438+
// filter containers by exact match
439+
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me")
440+
if out, _, err = runCommandWithOutput(runCmd); err != nil {
441+
t.Fatal(out, err)
442+
}
443+
containerOut := strings.TrimSpace(out)
444+
if containerOut != firstID {
445+
t.Fatalf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out)
446+
}
447+
448+
// filter containers by exact key
449+
runCmd = exec.Command(dockerBinary, "ps", "-a", "-q", "--no-trunc", "--filter=label=match")
450+
if out, _, err = runCommandWithOutput(runCmd); err != nil {
451+
t.Fatal(out, err)
452+
}
453+
containerOut = strings.TrimSpace(out)
454+
if (!strings.Contains(containerOut, firstID) || !strings.Contains(containerOut, secondID)) || strings.Contains(containerOut, thirdID) {
455+
t.Fatalf("Expected ids %s,%s, got %s for exited filter, output: %q", firstID, secondID, containerOut, out)
456+
}
457+
458+
deleteAllContainers()
459+
460+
logDone("ps - test ps filter label")
461+
}
462+
415463
func TestPsListContainersFilterExited(t *testing.T) {
416464
defer deleteAllContainers()
417465

integration-cli/docker_utils.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,15 @@ COPY . /static`); err != nil {
724724
ctx: ctx}, nil
725725
}
726726

727+
func inspectFieldAndMarshall(name, field string, output interface{}) error {
728+
str, err := inspectFieldJSON(name, field)
729+
if err != nil {
730+
return err
731+
}
732+
733+
return json.Unmarshal([]byte(str), output)
734+
}
735+
727736
func inspectFilter(name, filter string) (string, error) {
728737
format := fmt.Sprintf("{{%s}}", filter)
729738
inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)

pkg/parsers/filters/parse.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,38 @@ func FromParam(p string) (Args, error) {
6565
return args, nil
6666
}
6767

68+
func (filters Args) MatchKVList(field string, sources map[string]string) bool {
69+
fieldValues := filters[field]
70+
71+
//do not filter if there is no filter set or cannot determine filter
72+
if len(fieldValues) == 0 {
73+
return true
74+
}
75+
76+
if sources == nil || len(sources) == 0 {
77+
return false
78+
}
79+
80+
outer:
81+
for _, name2match := range fieldValues {
82+
testKV := strings.SplitN(name2match, "=", 2)
83+
84+
for k, v := range sources {
85+
if len(testKV) == 1 {
86+
if k == testKV[0] {
87+
continue outer
88+
}
89+
} else if k == testKV[0] && v == testKV[1] {
90+
continue outer
91+
}
92+
}
93+
94+
return false
95+
}
96+
97+
return true
98+
}
99+
68100
func (filters Args) Match(field, source string) bool {
69101
fieldValues := filters[field]
70102

0 commit comments

Comments
 (0)