Using Config.Labels to filter images on Labels.
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
| ... | ... |
@@ -108,17 +108,19 @@ func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image, |
| 108 | 108 |
} else {
|
| 109 | 109 |
// get the boolean list for if only the untagged images are requested |
| 110 | 110 |
delete(allImages, id) |
| 111 |
- if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) {
|
|
| 112 |
- continue |
|
| 111 |
+ |
|
| 112 |
+ if len(imageFilters["label"]) > 0 {
|
|
| 113 |
+ if image.Config == nil {
|
|
| 114 |
+ // Very old image that do not have image.Config (or even labels) |
|
| 115 |
+ continue |
|
| 116 |
+ } |
|
| 117 |
+ // We are now sure image.Config is not nil |
|
| 118 |
+ if !imageFilters.MatchKVList("label", image.Config.Labels) {
|
|
| 119 |
+ continue |
|
| 120 |
+ } |
|
| 113 | 121 |
} |
| 114 | 122 |
if filtTagged {
|
| 115 |
- newImage := new(types.Image) |
|
| 116 |
- newImage.ParentID = image.Parent |
|
| 117 |
- newImage.ID = image.ID |
|
| 118 |
- newImage.Created = image.Created.Unix() |
|
| 119 |
- newImage.Size = image.Size |
|
| 120 |
- newImage.VirtualSize = s.graph.GetParentsSize(image) + image.Size |
|
| 121 |
- newImage.Labels = image.ContainerConfig.Labels |
|
| 123 |
+ newImage := newImage(image, s.graph.GetParentsSize(image)) |
|
| 122 | 124 |
|
| 123 | 125 |
if utils.DigestReference(ref) {
|
| 124 | 126 |
newImage.RepoTags = []string{}
|
| ... | ... |
@@ -144,18 +146,19 @@ func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image, |
| 144 | 144 |
// Display images which aren't part of a repository/tag |
| 145 | 145 |
if filter == "" || filtLabel {
|
| 146 | 146 |
for _, image := range allImages {
|
| 147 |
- if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) {
|
|
| 148 |
- continue |
|
| 147 |
+ if len(imageFilters["label"]) > 0 {
|
|
| 148 |
+ if image.Config == nil {
|
|
| 149 |
+ // Very old image that do not have image.Config (or even labels) |
|
| 150 |
+ continue |
|
| 151 |
+ } |
|
| 152 |
+ // We are now sure image.Config is not nil |
|
| 153 |
+ if !imageFilters.MatchKVList("label", image.Config.Labels) {
|
|
| 154 |
+ continue |
|
| 155 |
+ } |
|
| 149 | 156 |
} |
| 150 |
- newImage := new(types.Image) |
|
| 151 |
- newImage.ParentID = image.Parent |
|
| 157 |
+ newImage := newImage(image, s.graph.GetParentsSize(image)) |
|
| 152 | 158 |
newImage.RepoTags = []string{"<none>:<none>"}
|
| 153 | 159 |
newImage.RepoDigests = []string{"<none>@<none>"}
|
| 154 |
- newImage.ID = image.ID |
|
| 155 |
- newImage.Created = image.Created.Unix() |
|
| 156 |
- newImage.Size = image.Size |
|
| 157 |
- newImage.VirtualSize = s.graph.GetParentsSize(image) + image.Size |
|
| 158 |
- newImage.Labels = image.ContainerConfig.Labels |
|
| 159 | 160 |
|
| 160 | 161 |
images = append(images, newImage) |
| 161 | 162 |
} |
| ... | ... |
@@ -165,3 +168,16 @@ func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image, |
| 165 | 165 |
|
| 166 | 166 |
return images, nil |
| 167 | 167 |
} |
| 168 |
+ |
|
| 169 |
+func newImage(image *image.Image, parentSize int64) *types.Image {
|
|
| 170 |
+ newImage := new(types.Image) |
|
| 171 |
+ newImage.ParentID = image.Parent |
|
| 172 |
+ newImage.ID = image.ID |
|
| 173 |
+ newImage.Created = image.Created.Unix() |
|
| 174 |
+ newImage.Size = image.Size |
|
| 175 |
+ newImage.VirtualSize = parentSize + image.Size |
|
| 176 |
+ if image.Config != nil {
|
|
| 177 |
+ newImage.Labels = image.Config.Labels |
|
| 178 |
+ } |
|
| 179 |
+ return newImage |
|
| 180 |
+} |
| ... | ... |
@@ -100,35 +100,40 @@ func (s *DockerSuite) TestImagesFilterLabel(c *check.C) {
|
| 100 | 100 |
image1ID, err := buildImage(imageName1, |
| 101 | 101 |
`FROM scratch |
| 102 | 102 |
LABEL match me`, true) |
| 103 |
- if err != nil {
|
|
| 104 |
- c.Fatal(err) |
|
| 105 |
- } |
|
| 103 |
+ c.Assert(err, check.IsNil) |
|
| 106 | 104 |
|
| 107 | 105 |
image2ID, err := buildImage(imageName2, |
| 108 | 106 |
`FROM scratch |
| 109 | 107 |
LABEL match="me too"`, true) |
| 110 |
- if err != nil {
|
|
| 111 |
- c.Fatal(err) |
|
| 112 |
- } |
|
| 108 |
+ c.Assert(err, check.IsNil) |
|
| 113 | 109 |
|
| 114 | 110 |
image3ID, err := buildImage(imageName3, |
| 115 | 111 |
`FROM scratch |
| 116 | 112 |
LABEL nomatch me`, true) |
| 117 |
- if err != nil {
|
|
| 118 |
- c.Fatal(err) |
|
| 119 |
- } |
|
| 113 |
+ c.Assert(err, check.IsNil) |
|
| 120 | 114 |
|
| 121 | 115 |
out, _ := dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=match") |
| 122 | 116 |
out = strings.TrimSpace(out) |
| 123 |
- if (!strings.Contains(out, image1ID) && !strings.Contains(out, image2ID)) || strings.Contains(out, image3ID) {
|
|
| 124 |
- c.Fatalf("Expected ids %s,%s got %s", image1ID, image2ID, out)
|
|
| 125 |
- } |
|
| 117 |
+ c.Assert(out, check.Matches, fmt.Sprintf("[\\s\\w]*%s[\\s\\w]*", image1ID))
|
|
| 118 |
+ c.Assert(out, check.Matches, fmt.Sprintf("[\\s\\w]*%s[\\s\\w]*", image2ID))
|
|
| 119 |
+ c.Assert(out, check.Not(check.Matches), fmt.Sprintf("[\\s\\w]*%s[\\s\\w]*", image3ID))
|
|
| 126 | 120 |
|
| 127 | 121 |
out, _ = dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=match=me too") |
| 128 | 122 |
out = strings.TrimSpace(out) |
| 129 |
- if out != image2ID {
|
|
| 130 |
- c.Fatalf("Expected %s got %s", image2ID, out)
|
|
| 131 |
- } |
|
| 123 |
+ c.Assert(out, check.Equals, image2ID) |
|
| 124 |
+} |
|
| 125 |
+ |
|
| 126 |
+// Regression : #15659 |
|
| 127 |
+func (s *DockerSuite) TestImagesFilterLabelWithCommit(c *check.C) {
|
|
| 128 |
+ // Create a container |
|
| 129 |
+ dockerCmd(c, "run", "--name", "bar", "busybox", "/bin/sh") |
|
| 130 |
+ // Commit with labels "using changes" |
|
| 131 |
+ out, _ := dockerCmd(c, "commit", "-c", "LABEL foo.version=1.0.0-1", "-c", "LABEL foo.name=bar", "-c", "LABEL foo.author=starlord", "bar", "bar:1.0.0-1") |
|
| 132 |
+ imageID := strings.TrimSpace(out) |
|
| 133 |
+ |
|
| 134 |
+ out, _ = dockerCmd(c, "images", "--no-trunc", "-q", "-f", "label=foo.version=1.0.0-1") |
|
| 135 |
+ out = strings.TrimSpace(out) |
|
| 136 |
+ c.Assert(out, check.Equals, imageID) |
|
| 132 | 137 |
} |
| 133 | 138 |
|
| 134 | 139 |
func (s *DockerSuite) TestImagesFilterSpaceTrimCase(c *check.C) {
|
| ... | ... |
@@ -104,6 +104,10 @@ func (s *DockerSuite) TestSaveImageId(c *check.C) {
|
| 104 | 104 |
out, _ = dockerCmd(c, "images", "-q", repoName) |
| 105 | 105 |
cleanedShortImageID := strings.TrimSpace(out) |
| 106 | 106 |
|
| 107 |
+ // Make sure IDs are not empty |
|
| 108 |
+ c.Assert(cleanedLongImageID, check.Not(check.Equals), "", check.Commentf("Id should not be empty."))
|
|
| 109 |
+ c.Assert(cleanedShortImageID, check.Not(check.Equals), "", check.Commentf("Id should not be empty."))
|
|
| 110 |
+ |
|
| 107 | 111 |
saveCmd := exec.Command(dockerBinary, "save", cleanedShortImageID) |
| 108 | 112 |
tarCmd := exec.Command("tar", "t")
|
| 109 | 113 |
|