image_list.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. package images // import "github.com/docker/docker/daemon/images"
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "sort"
  7. "time"
  8. "github.com/distribution/reference"
  9. "github.com/docker/docker/api/types"
  10. imagetypes "github.com/docker/docker/api/types/image"
  11. timetypes "github.com/docker/docker/api/types/time"
  12. "github.com/docker/docker/container"
  13. "github.com/docker/docker/image"
  14. "github.com/docker/docker/layer"
  15. )
  16. var acceptedImageFilterTags = map[string]bool{
  17. "dangling": true,
  18. "label": true,
  19. "before": true,
  20. "since": true,
  21. "reference": true,
  22. "until": true,
  23. }
  24. // byCreated is a temporary type used to sort a list of images by creation
  25. // time.
  26. type byCreated []*imagetypes.Summary
  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. // Images returns a filtered list of images.
  31. func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions) ([]*imagetypes.Summary, error) {
  32. if err := opts.Filters.Validate(acceptedImageFilterTags); err != nil {
  33. return nil, err
  34. }
  35. danglingOnly, err := opts.Filters.GetBoolOrDefault("dangling", false)
  36. if err != nil {
  37. return nil, err
  38. }
  39. var beforeFilter, sinceFilter time.Time
  40. err = opts.Filters.WalkValues("before", func(value string) error {
  41. img, err := i.GetImage(ctx, value, imagetypes.GetImageOpts{})
  42. if err != nil {
  43. return err
  44. }
  45. // Resolve multiple values to the oldest image,
  46. // equivalent to ANDing all the values together.
  47. if img.Created != nil && (beforeFilter.IsZero() || beforeFilter.After(*img.Created)) {
  48. beforeFilter = *img.Created
  49. }
  50. return nil
  51. })
  52. if err != nil {
  53. return nil, err
  54. }
  55. err = opts.Filters.WalkValues("until", func(value string) error {
  56. ts, err := timetypes.GetTimestamp(value, time.Now())
  57. if err != nil {
  58. return err
  59. }
  60. seconds, nanoseconds, err := timetypes.ParseTimestamps(ts, 0)
  61. if err != nil {
  62. return err
  63. }
  64. timestamp := time.Unix(seconds, nanoseconds)
  65. if beforeFilter.IsZero() || beforeFilter.After(timestamp) {
  66. beforeFilter = timestamp
  67. }
  68. return nil
  69. })
  70. if err != nil {
  71. return nil, err
  72. }
  73. err = opts.Filters.WalkValues("since", func(value string) error {
  74. img, err := i.GetImage(ctx, value, imagetypes.GetImageOpts{})
  75. if err != nil {
  76. return err
  77. }
  78. // Resolve multiple values to the newest image,
  79. // equivalent to ANDing all the values together.
  80. if img.Created != nil && sinceFilter.Before(*img.Created) {
  81. sinceFilter = *img.Created
  82. }
  83. return nil
  84. })
  85. if err != nil {
  86. return nil, err
  87. }
  88. var selectedImages map[image.ID]*image.Image
  89. if danglingOnly {
  90. selectedImages = i.imageStore.Heads()
  91. } else {
  92. selectedImages = i.imageStore.Map()
  93. }
  94. var (
  95. summaries = make([]*imagetypes.Summary, 0, len(selectedImages))
  96. summaryMap map[*image.Image]*imagetypes.Summary
  97. allContainers []*container.Container
  98. )
  99. for id, img := range selectedImages {
  100. select {
  101. case <-ctx.Done():
  102. return nil, ctx.Err()
  103. default:
  104. }
  105. if !beforeFilter.IsZero() && (img.Created == nil || !img.Created.Before(beforeFilter)) {
  106. continue
  107. }
  108. if !sinceFilter.IsZero() && (img.Created == nil || !img.Created.After(sinceFilter)) {
  109. continue
  110. }
  111. if opts.Filters.Contains("label") {
  112. // Very old image that do not have image.Config (or even labels)
  113. if img.Config == nil {
  114. continue
  115. }
  116. // We are now sure image.Config is not nil
  117. if !opts.Filters.MatchKVList("label", img.Config.Labels) {
  118. continue
  119. }
  120. }
  121. // Skip any images with an unsupported operating system to avoid a potential
  122. // panic when indexing through the layerstore. Don't error as we want to list
  123. // the other images. This should never happen, but here as a safety precaution.
  124. if err := image.CheckOS(img.OperatingSystem()); err != nil {
  125. continue
  126. }
  127. var size int64
  128. if layerID := img.RootFS.ChainID(); layerID != "" {
  129. l, err := i.layerStore.Get(layerID)
  130. if err != nil {
  131. // The layer may have been deleted between the call to `Map()` or
  132. // `Heads()` and the call to `Get()`, so we just ignore this error
  133. if errors.Is(err, layer.ErrLayerDoesNotExist) {
  134. continue
  135. }
  136. return nil, err
  137. }
  138. size = l.Size()
  139. layer.ReleaseAndLog(i.layerStore, l)
  140. }
  141. summary := newImageSummary(img, size)
  142. for _, ref := range i.referenceStore.References(id.Digest()) {
  143. if opts.Filters.Contains("reference") {
  144. var found bool
  145. var matchErr error
  146. for _, pattern := range opts.Filters.Get("reference") {
  147. found, matchErr = reference.FamiliarMatch(pattern, ref)
  148. if matchErr != nil {
  149. return nil, matchErr
  150. }
  151. if found {
  152. break
  153. }
  154. }
  155. if !found {
  156. continue
  157. }
  158. }
  159. if _, ok := ref.(reference.Canonical); ok {
  160. summary.RepoDigests = append(summary.RepoDigests, reference.FamiliarString(ref))
  161. }
  162. if _, ok := ref.(reference.NamedTagged); ok {
  163. summary.RepoTags = append(summary.RepoTags, reference.FamiliarString(ref))
  164. }
  165. }
  166. if summary.RepoDigests == nil && summary.RepoTags == nil {
  167. if opts.All || len(i.imageStore.Children(id)) == 0 {
  168. if opts.Filters.Contains("dangling") && !danglingOnly {
  169. // dangling=false case, so dangling image is not needed
  170. continue
  171. }
  172. if opts.Filters.Contains("reference") { // skip images with no references if filtering by reference
  173. continue
  174. }
  175. } else {
  176. continue
  177. }
  178. } else if danglingOnly && len(summary.RepoTags) > 0 {
  179. continue
  180. }
  181. if opts.ContainerCount {
  182. // Lazily init allContainers.
  183. if allContainers == nil {
  184. allContainers = i.containers.List()
  185. }
  186. // Get container count
  187. var containers int64
  188. for _, c := range allContainers {
  189. if c.ImageID == id {
  190. containers++
  191. }
  192. }
  193. // NOTE: By default, Containers is -1, or "not set"
  194. summary.Containers = containers
  195. }
  196. if opts.ContainerCount || opts.SharedSize {
  197. // Lazily init summaryMap.
  198. if summaryMap == nil {
  199. summaryMap = make(map[*image.Image]*imagetypes.Summary, len(selectedImages))
  200. }
  201. summaryMap[img] = summary
  202. }
  203. summaries = append(summaries, summary)
  204. }
  205. if opts.SharedSize {
  206. allLayers := i.layerStore.Map()
  207. layerRefs := make(map[layer.ChainID]int, len(allLayers))
  208. allImages := selectedImages
  209. if danglingOnly {
  210. // If danglingOnly is true, then selectedImages include only dangling images,
  211. // but we need to consider all existing images to correctly perform reference counting.
  212. // If danglingOnly is false, selectedImages (and, hence, allImages) is already equal to i.imageStore.Map()
  213. // and we can avoid performing an otherwise redundant method call.
  214. allImages = i.imageStore.Map()
  215. }
  216. // Count layer references across all known images
  217. for _, img := range allImages {
  218. rootFS := *img.RootFS
  219. rootFS.DiffIDs = nil
  220. for _, id := range img.RootFS.DiffIDs {
  221. rootFS.Append(id)
  222. layerRefs[rootFS.ChainID()]++
  223. }
  224. }
  225. // Get Shared sizes
  226. for img, summary := range summaryMap {
  227. rootFS := *img.RootFS
  228. rootFS.DiffIDs = nil
  229. // Indicate that we collected shared size information (default is -1, or "not set")
  230. summary.SharedSize = 0
  231. for _, id := range img.RootFS.DiffIDs {
  232. rootFS.Append(id)
  233. chid := rootFS.ChainID()
  234. if layerRefs[chid] > 1 {
  235. if _, ok := allLayers[chid]; !ok {
  236. return nil, fmt.Errorf("layer %v was not found (corruption?)", chid)
  237. }
  238. summary.SharedSize += allLayers[chid].DiffSize()
  239. }
  240. }
  241. }
  242. }
  243. sort.Sort(sort.Reverse(byCreated(summaries)))
  244. return summaries, nil
  245. }
  246. func newImageSummary(image *image.Image, size int64) *imagetypes.Summary {
  247. var created int64
  248. if image.Created != nil {
  249. created = image.Created.Unix()
  250. }
  251. summary := &imagetypes.Summary{
  252. ParentID: image.Parent.String(),
  253. ID: image.ID().String(),
  254. Created: created,
  255. Size: size,
  256. // -1 indicates that the value has not been set (avoids ambiguity
  257. // between 0 (default) and "not set". We cannot use a pointer (nil)
  258. // for this, as the JSON representation uses "omitempty", which would
  259. // consider both "0" and "nil" to be "empty".
  260. SharedSize: -1,
  261. Containers: -1,
  262. }
  263. if image.Config != nil {
  264. summary.Labels = image.Config.Labels
  265. }
  266. return summary
  267. }