github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/daemon/images.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"path"
     6  	"sort"
     7  
     8  	"github.com/docker/docker/image"
     9  	"github.com/docker/docker/layer"
    10  	"github.com/docker/docker/reference"
    11  	"github.com/docker/engine-api/types"
    12  	"github.com/docker/engine-api/types/filters"
    13  )
    14  
    15  var acceptedImageFilterTags = map[string]bool{
    16  	"dangling": true,
    17  	"label":    true,
    18  }
    19  
    20  // byCreated is a temporary type used to sort a list of images by creation
    21  // time.
    22  type byCreated []*types.Image
    23  
    24  func (r byCreated) Len() int           { return len(r) }
    25  func (r byCreated) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
    26  func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
    27  
    28  // Map returns a map of all images in the ImageStore
    29  func (daemon *Daemon) Map() map[image.ID]*image.Image {
    30  	return daemon.imageStore.Map()
    31  }
    32  
    33  // Images returns a filtered list of images. filterArgs is a JSON-encoded set
    34  // of filter arguments which will be interpreted by api/types/filters.
    35  // filter is a shell glob string applied to repository names. The argument
    36  // named all controls whether all images in the graph are filtered, or just
    37  // the heads.
    38  func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Image, error) {
    39  	var (
    40  		allImages    map[image.ID]*image.Image
    41  		err          error
    42  		danglingOnly = false
    43  	)
    44  
    45  	imageFilters, err := filters.FromParam(filterArgs)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	if err := imageFilters.Validate(acceptedImageFilterTags); err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	if imageFilters.Include("dangling") {
    54  		if imageFilters.ExactMatch("dangling", "true") {
    55  			danglingOnly = true
    56  		} else if !imageFilters.ExactMatch("dangling", "false") {
    57  			return nil, fmt.Errorf("Invalid filter 'dangling=%s'", imageFilters.Get("dangling"))
    58  		}
    59  	}
    60  	if danglingOnly {
    61  		allImages = daemon.imageStore.Heads()
    62  	} else {
    63  		allImages = daemon.imageStore.Map()
    64  	}
    65  
    66  	images := []*types.Image{}
    67  
    68  	var filterTagged bool
    69  	if filter != "" {
    70  		filterRef, err := reference.ParseNamed(filter)
    71  		if err == nil { // parse error means wildcard repo
    72  			if _, ok := filterRef.(reference.NamedTagged); ok {
    73  				filterTagged = true
    74  			}
    75  		}
    76  	}
    77  
    78  	for id, img := range allImages {
    79  		if imageFilters.Include("label") {
    80  			// Very old image that do not have image.Config (or even labels)
    81  			if img.Config == nil {
    82  				continue
    83  			}
    84  			// We are now sure image.Config is not nil
    85  			if !imageFilters.MatchKVList("label", img.Config.Labels) {
    86  				continue
    87  			}
    88  		}
    89  
    90  		layerID := img.RootFS.ChainID()
    91  		var size int64
    92  		if layerID != "" {
    93  			l, err := daemon.layerStore.Get(layerID)
    94  			if err != nil {
    95  				return nil, err
    96  			}
    97  
    98  			size, err = l.Size()
    99  			layer.ReleaseAndLog(daemon.layerStore, l)
   100  			if err != nil {
   101  				return nil, err
   102  			}
   103  		}
   104  
   105  		newImage := newImage(img, size)
   106  
   107  		for _, ref := range daemon.referenceStore.References(id) {
   108  			if filter != "" { // filter by tag/repo name
   109  				if filterTagged { // filter by tag, require full ref match
   110  					if ref.String() != filter {
   111  						continue
   112  					}
   113  				} else if matched, err := path.Match(filter, ref.Name()); !matched || err != nil { // name only match, FIXME: docs say exact
   114  					continue
   115  				}
   116  			}
   117  			if _, ok := ref.(reference.Canonical); ok {
   118  				newImage.RepoDigests = append(newImage.RepoDigests, ref.String())
   119  			}
   120  			if _, ok := ref.(reference.NamedTagged); ok {
   121  				newImage.RepoTags = append(newImage.RepoTags, ref.String())
   122  			}
   123  		}
   124  		if newImage.RepoDigests == nil && newImage.RepoTags == nil {
   125  			if all || len(daemon.imageStore.Children(id)) == 0 {
   126  
   127  				if imageFilters.Include("dangling") && !danglingOnly {
   128  					//dangling=false case, so dangling image is not needed
   129  					continue
   130  				}
   131  				if filter != "" { // skip images with no references if filtering by tag
   132  					continue
   133  				}
   134  				newImage.RepoDigests = []string{"<none>@<none>"}
   135  				newImage.RepoTags = []string{"<none>:<none>"}
   136  			} else {
   137  				continue
   138  			}
   139  		} else if danglingOnly {
   140  			continue
   141  		}
   142  
   143  		images = append(images, newImage)
   144  	}
   145  
   146  	sort.Sort(sort.Reverse(byCreated(images)))
   147  
   148  	return images, nil
   149  }
   150  
   151  func newImage(image *image.Image, size int64) *types.Image {
   152  	newImage := new(types.Image)
   153  	newImage.ParentID = image.Parent.String()
   154  	newImage.ID = image.ID().String()
   155  	newImage.Created = image.Created.Unix()
   156  	newImage.Size = size
   157  	newImage.VirtualSize = size
   158  	if image.Config != nil {
   159  		newImage.Labels = image.Config.Labels
   160  	}
   161  	return newImage
   162  }