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