github.com/kim0/docker@v0.6.2-0.20161130212042-4addda3f07e7/daemon/images.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "path" 6 "sort" 7 8 "github.com/docker/docker/api/types" 9 "github.com/docker/docker/api/types/filters" 10 "github.com/docker/docker/container" 11 "github.com/docker/docker/image" 12 "github.com/docker/docker/layer" 13 "github.com/docker/docker/reference" 14 ) 15 16 var acceptedImageFilterTags = map[string]bool{ 17 "dangling": true, 18 "label": true, 19 "before": true, 20 "since": true, 21 } 22 23 // byCreated is a temporary type used to sort a list of images by creation 24 // time. 25 type byCreated []*types.ImageSummary 26 27 func (r byCreated) Len() int { return len(r) } 28 func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] } 29 func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created } 30 31 // Map returns a map of all images in the ImageStore 32 func (daemon *Daemon) Map() map[image.ID]*image.Image { 33 return daemon.imageStore.Map() 34 } 35 36 // Images returns a filtered list of images. filterArgs is a JSON-encoded set 37 // of filter arguments which will be interpreted by api/types/filters. 38 // filter is a shell glob string applied to repository names. The argument 39 // named all controls whether all images in the graph are filtered, or just 40 // the heads. 41 func (daemon *Daemon) Images(filterArgs, filter string, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error) { 42 var ( 43 allImages map[image.ID]*image.Image 44 err error 45 danglingOnly = false 46 ) 47 48 imageFilters, err := filters.FromParam(filterArgs) 49 if err != nil { 50 return nil, err 51 } 52 if err := imageFilters.Validate(acceptedImageFilterTags); err != nil { 53 return nil, err 54 } 55 56 if imageFilters.Include("dangling") { 57 if imageFilters.ExactMatch("dangling", "true") { 58 danglingOnly = true 59 } else if !imageFilters.ExactMatch("dangling", "false") { 60 return nil, fmt.Errorf("Invalid filter 'dangling=%s'", imageFilters.Get("dangling")) 61 } 62 } 63 if danglingOnly { 64 allImages = daemon.imageStore.Heads() 65 } else { 66 allImages = daemon.imageStore.Map() 67 } 68 69 var beforeFilter, sinceFilter *image.Image 70 err = imageFilters.WalkValues("before", func(value string) error { 71 beforeFilter, err = daemon.GetImage(value) 72 return err 73 }) 74 if err != nil { 75 return nil, err 76 } 77 78 err = imageFilters.WalkValues("since", func(value string) error { 79 sinceFilter, err = daemon.GetImage(value) 80 return err 81 }) 82 if err != nil { 83 return nil, err 84 } 85 86 images := []*types.ImageSummary{} 87 var imagesMap map[*image.Image]*types.ImageSummary 88 var layerRefs map[layer.ChainID]int 89 var allLayers map[layer.ChainID]layer.Layer 90 var allContainers []*container.Container 91 92 var filterTagged bool 93 if filter != "" { 94 filterRef, err := reference.ParseNamed(filter) 95 if err == nil { // parse error means wildcard repo 96 if _, ok := filterRef.(reference.NamedTagged); ok { 97 filterTagged = true 98 } 99 } 100 } 101 102 for id, img := range allImages { 103 if beforeFilter != nil { 104 if img.Created.Equal(beforeFilter.Created) || img.Created.After(beforeFilter.Created) { 105 continue 106 } 107 } 108 109 if sinceFilter != nil { 110 if img.Created.Equal(sinceFilter.Created) || img.Created.Before(sinceFilter.Created) { 111 continue 112 } 113 } 114 115 if imageFilters.Include("label") { 116 // Very old image that do not have image.Config (or even labels) 117 if img.Config == nil { 118 continue 119 } 120 // We are now sure image.Config is not nil 121 if !imageFilters.MatchKVList("label", img.Config.Labels) { 122 continue 123 } 124 } 125 126 layerID := img.RootFS.ChainID() 127 var size int64 128 if layerID != "" { 129 l, err := daemon.layerStore.Get(layerID) 130 if err != nil { 131 return nil, err 132 } 133 134 size, err = l.Size() 135 layer.ReleaseAndLog(daemon.layerStore, l) 136 if err != nil { 137 return nil, err 138 } 139 } 140 141 newImage := newImage(img, size) 142 143 for _, ref := range daemon.referenceStore.References(id.Digest()) { 144 if filter != "" { // filter by tag/repo name 145 if filterTagged { // filter by tag, require full ref match 146 if ref.String() != filter { 147 continue 148 } 149 } else if matched, err := path.Match(filter, ref.Name()); !matched || err != nil { // name only match, FIXME: docs say exact 150 continue 151 } 152 } 153 if _, ok := ref.(reference.Canonical); ok { 154 newImage.RepoDigests = append(newImage.RepoDigests, ref.String()) 155 } 156 if _, ok := ref.(reference.NamedTagged); ok { 157 newImage.RepoTags = append(newImage.RepoTags, ref.String()) 158 } 159 } 160 if newImage.RepoDigests == nil && newImage.RepoTags == nil { 161 if all || len(daemon.imageStore.Children(id)) == 0 { 162 163 if imageFilters.Include("dangling") && !danglingOnly { 164 //dangling=false case, so dangling image is not needed 165 continue 166 } 167 if filter != "" { // skip images with no references if filtering by tag 168 continue 169 } 170 newImage.RepoDigests = []string{"<none>@<none>"} 171 newImage.RepoTags = []string{"<none>:<none>"} 172 } else { 173 continue 174 } 175 } else if danglingOnly && len(newImage.RepoTags) > 0 { 176 continue 177 } 178 179 if withExtraAttrs { 180 // lazyly init variables 181 if imagesMap == nil { 182 allContainers = daemon.List() 183 allLayers = daemon.layerStore.Map() 184 imagesMap = make(map[*image.Image]*types.ImageSummary) 185 layerRefs = make(map[layer.ChainID]int) 186 } 187 188 // Get container count 189 newImage.Containers = 0 190 for _, c := range allContainers { 191 if c.ImageID == id { 192 newImage.Containers++ 193 } 194 } 195 196 // count layer references 197 rootFS := *img.RootFS 198 rootFS.DiffIDs = nil 199 for _, id := range img.RootFS.DiffIDs { 200 rootFS.Append(id) 201 chid := rootFS.ChainID() 202 layerRefs[chid]++ 203 if _, ok := allLayers[chid]; !ok { 204 return nil, fmt.Errorf("layer %v was not found (corruption?)", chid) 205 } 206 } 207 imagesMap[img] = newImage 208 } 209 210 images = append(images, newImage) 211 } 212 213 if withExtraAttrs { 214 // Get Shared and Unique sizes 215 for img, newImage := range imagesMap { 216 rootFS := *img.RootFS 217 rootFS.DiffIDs = nil 218 219 newImage.Size = 0 220 newImage.SharedSize = 0 221 for _, id := range img.RootFS.DiffIDs { 222 rootFS.Append(id) 223 chid := rootFS.ChainID() 224 225 diffSize, err := allLayers[chid].DiffSize() 226 if err != nil { 227 return nil, err 228 } 229 230 if layerRefs[chid] > 1 { 231 newImage.SharedSize += diffSize 232 } else { 233 newImage.Size += diffSize 234 } 235 } 236 } 237 } 238 239 sort.Sort(sort.Reverse(byCreated(images))) 240 241 return images, nil 242 } 243 244 func newImage(image *image.Image, virtualSize int64) *types.ImageSummary { 245 newImage := new(types.ImageSummary) 246 newImage.ParentID = image.Parent.String() 247 newImage.ID = image.ID().String() 248 newImage.Created = image.Created.Unix() 249 newImage.Size = -1 250 newImage.VirtualSize = virtualSize 251 newImage.SharedSize = -1 252 newImage.Containers = -1 253 if image.Config != nil { 254 newImage.Labels = image.Config.Labels 255 } 256 return newImage 257 }