func (s *TagStore) CmdImages(job *engine.Job) error { var ( allImages map[string]*image.Image err error filt_tagged = true filt_label = false ) imageFilters, err := filters.FromParam(job.Getenv("filters")) if err != nil { return err } for name := range imageFilters { if _, ok := acceptedImageFilterTags[name]; !ok { return fmt.Errorf("Invalid filter '%s'", name) } } if i, ok := imageFilters["dangling"]; ok { for _, value := range i { if strings.ToLower(value) == "true" { filt_tagged = false } } } _, filt_label = imageFilters["label"] if job.GetenvBool("all") && filt_tagged { allImages, err = s.graph.Map() } else { allImages, err = s.graph.Heads() } if err != nil { return err } lookup := make(map[string]*engine.Env) s.Lock() for repoName, repository := range s.Repositories { if job.Getenv("filter") != "" { if match, _ := path.Match(job.Getenv("filter"), repoName); !match { continue } } for ref, id := range repository { imgRef := utils.ImageReference(repoName, ref) image, err := s.graph.Get(id) if err != nil { log.Printf("Warning: couldn't load %s from %s: %s", id, imgRef, err) continue } if out, exists := lookup[id]; exists { if filt_tagged { if utils.DigestReference(ref) { out.SetList("RepoDigests", append(out.GetList("RepoDigests"), imgRef)) } else { // Tag Ref. out.SetList("RepoTags", append(out.GetList("RepoTags"), imgRef)) } } } else { // get the boolean list for if only the untagged images are requested delete(allImages, id) if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) { continue } if filt_tagged { out := &engine.Env{} out.SetJson("ParentId", image.Parent) out.SetJson("Id", image.ID) out.SetInt64("Created", image.Created.Unix()) out.SetInt64("Size", image.Size) out.SetInt64("VirtualSize", image.GetParentsSize(0)+image.Size) out.SetJson("Labels", image.ContainerConfig.Labels) if utils.DigestReference(ref) { out.SetList("RepoTags", []string{}) out.SetList("RepoDigests", []string{imgRef}) } else { out.SetList("RepoTags", []string{imgRef}) out.SetList("RepoDigests", []string{}) } lookup[id] = out } } } } s.Unlock() outs := engine.NewTable("Created", len(lookup)) for _, value := range lookup { outs.Add(value) } // Display images which aren't part of a repository/tag if job.Getenv("filter") == "" || filt_label { for _, image := range allImages { if !imageFilters.MatchKVList("label", image.ContainerConfig.Labels) { continue } out := &engine.Env{} out.SetJson("ParentId", image.Parent) out.SetList("RepoTags", []string{"<none>:<none>"}) out.SetList("RepoDigests", []string{"<none>@<none>"}) out.SetJson("Id", image.ID) out.SetInt64("Created", image.Created.Unix()) out.SetInt64("Size", image.Size) out.SetInt64("VirtualSize", image.GetParentsSize(0)+image.Size) out.SetJson("Labels", image.ContainerConfig.Labels) outs.Add(out) } } outs.ReverseSort() if _, err := outs.WriteListTo(job.Stdout); err != nil { return err } return nil }
// Images returns a filtered list of images. filterArgs is a JSON-encoded set // of filter arguments which will be interpreted by pkg/parsers/filters. // filter is a shell glob string applied to repository names. The argument // named all controls whether all images in the graph are filtered, or just // the heads. func (s *TagStore) Images(filterArgs, filter string, all bool) ([]*types.Image, error) { var ( allImages map[string]*image.Image err error filtTagged = true filtLabel = false ) imageFilters, err := filters.FromParam(filterArgs) if err != nil { return nil, err } for name := range imageFilters { if _, ok := acceptedImageFilterTags[name]; !ok { return nil, fmt.Errorf("Invalid filter '%s'", name) } } if i, ok := imageFilters["dangling"]; ok { for _, value := range i { if v := strings.ToLower(value); v == "true" { filtTagged = false } else if v != "false" { return nil, fmt.Errorf("Invalid filter 'dangling=%s'", v) } } } _, filtLabel = imageFilters["label"] if all && filtTagged { allImages = s.graph.Map() } else { allImages = s.graph.Heads() } lookup := make(map[string]*types.Image) s.Lock() for repoName, repository := range s.Repositories { filterTagName := "" if filter != "" { filterName := filter // Test if the tag was in there, if yes, get the name if strings.Contains(filterName, ":") { filterWithTag := strings.Split(filter, ":") filterName = filterWithTag[0] filterTagName = filterWithTag[1] } if match, _ := path.Match(filterName, repoName); !match { continue } if filterTagName != "" { if _, ok := repository[filterTagName]; !ok { continue } } } for ref, id := range repository { imgRef := utils.ImageReference(repoName, ref) if !strings.Contains(imgRef, filterTagName) { continue } image, err := s.graph.Get(id) if err != nil { logrus.Warnf("couldn't load %s from %s: %s", id, imgRef, err) continue } if lImage, exists := lookup[id]; exists { if filtTagged { if utils.DigestReference(ref) { lImage.RepoDigests = append(lImage.RepoDigests, imgRef) } else { // Tag Ref. lImage.RepoTags = append(lImage.RepoTags, imgRef) } } } else { // get the boolean list for if only the untagged images are requested delete(allImages, id) if len(imageFilters["label"]) > 0 { if image.Config == nil { // Very old image that do not have image.Config (or even labels) continue } // We are now sure image.Config is not nil if !imageFilters.MatchKVList("label", image.Config.Labels) { continue } } if filtTagged { newImage := newImage(image, s.graph.GetParentsSize(image)) if utils.DigestReference(ref) { newImage.RepoTags = []string{} newImage.RepoDigests = []string{imgRef} } else { newImage.RepoTags = []string{imgRef} newImage.RepoDigests = []string{} } lookup[id] = newImage } } } } s.Unlock() images := []*types.Image{} for _, value := range lookup { images = append(images, value) } // Display images which aren't part of a repository/tag if filter == "" || filtLabel { for _, image := range allImages { if len(imageFilters["label"]) > 0 { if image.Config == nil { // Very old image that do not have image.Config (or even labels) continue } // We are now sure image.Config is not nil if !imageFilters.MatchKVList("label", image.Config.Labels) { continue } } newImage := newImage(image, s.graph.GetParentsSize(image)) newImage.RepoTags = []string{"<none>:<none>"} newImage.RepoDigests = []string{"<none>@<none>"} images = append(images, newImage) } } sort.Sort(sort.Reverse(byCreated(images))) return images, nil }