diff options
-rw-r--r-- | cmd/podman/images.go | 89 | ||||
-rw-r--r-- | libpod/image/image.go | 26 | ||||
-rw-r--r-- | libpod/image/utils.go | 20 | ||||
-rw-r--r-- | libpod/runtime_img.go | 146 |
4 files changed, 111 insertions, 170 deletions
diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 846f00c98..67f7920f2 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -10,7 +10,7 @@ import ( "github.com/pkg/errors" "github.com/projectatomic/libpod/cmd/podman/formats" "github.com/projectatomic/libpod/libpod" - "github.com/projectatomic/libpod/pkg/inspect" + "github.com/projectatomic/libpod/libpod/image" "github.com/urfave/cli" ) @@ -81,6 +81,10 @@ var ( ) func imagesCmd(c *cli.Context) error { + var ( + filterFuncs []libpod.ImageResultFilter + newImage *image.Image + ) if err := validateFlags(c, imagesFlags); err != nil { return err } @@ -90,18 +94,19 @@ func imagesCmd(c *cli.Context) error { return errors.Wrapf(err, "Could not get runtime") } defer runtime.Shutdown(false) - var filterFuncs []libpod.ImageResultFilter - var imageInput string if len(c.Args()) == 1 { - imageInput = c.Args().Get(0) + newImage, err = runtime.ImageRuntime().NewFromLocal(c.Args().Get(0)) + if err != nil { + return err + } } if len(c.Args()) > 1 { return errors.New("'podman images' requires at most 1 argument") } - if len(c.StringSlice("filter")) > 0 || len(strings.TrimSpace(imageInput)) != 0 { - filterFuncs, err = CreateFilterFuncs(runtime, c, imageInput) + if len(c.StringSlice("filter")) > 0 || newImage != nil { + filterFuncs, err = CreateFilterFuncs(runtime, c, newImage) if err != nil { return err } @@ -123,14 +128,14 @@ func imagesCmd(c *cli.Context) error { children to the image once built. until buildah supports caching builds, it will not generate these intermediate images. */ - images, err := runtime.GetImageResults() + images, err := runtime.ImageRuntime().GetImages() if err != nil { return errors.Wrapf(err, "unable to get images") } - var filteredImages []inspect.ImageResult + var filteredImages []*image.Image // filter the images - if len(c.StringSlice("filter")) > 0 || len(strings.TrimSpace(imageInput)) != 0 { + if len(c.StringSlice("filter")) > 0 || newImage != nil { filteredImages = libpod.FilterImages(images, filterFuncs) } else { filteredImages = images @@ -174,24 +179,28 @@ func imagesToGeneric(templParams []imagesTemplateParams, JSONParams []imagesJSON } // getImagesTemplateOutput returns the images information to be printed in human readable format -func getImagesTemplateOutput(runtime *libpod.Runtime, images []inspect.ImageResult, opts imagesOptions) (imagesOutput []imagesTemplateParams) { +func getImagesTemplateOutput(runtime *libpod.Runtime, images []*image.Image, opts imagesOptions) (imagesOutput []imagesTemplateParams) { for _, img := range images { - createdTime := img.Created + createdTime := img.Created() - imageID := "sha256:" + img.ID + imageID := "sha256:" + img.ID() if !opts.noTrunc { - imageID = shortID(img.ID) + imageID = shortID(img.ID()) } // get all specified repo:tag pairs and print them separately - for repo, tags := range libpod.ReposToMap(img.RepoTags) { + for repo, tags := range image.ReposToMap(img.Names()) { for _, tag := range tags { + size, err := img.Size() + if err != nil { + size = nil + } params := imagesTemplateParams{ Repository: repo, Tag: tag, ID: imageID, - Digest: img.Digest, + Digest: img.Digest(), Created: units.HumanDuration(time.Since((createdTime))) + " ago", - Size: units.HumanSizeWithPrecision(float64(*img.Size), 3), + Size: units.HumanSizeWithPrecision(float64(*size), 3), } imagesOutput = append(imagesOutput, params) } @@ -201,14 +210,18 @@ func getImagesTemplateOutput(runtime *libpod.Runtime, images []inspect.ImageResu } // getImagesJSONOutput returns the images information in its raw form -func getImagesJSONOutput(runtime *libpod.Runtime, images []inspect.ImageResult) (imagesOutput []imagesJSONParams) { +func getImagesJSONOutput(runtime *libpod.Runtime, images []*image.Image) (imagesOutput []imagesJSONParams) { for _, img := range images { + size, err := img.Size() + if err != nil { + size = nil + } params := imagesJSONParams{ - ID: img.ID, - Name: img.RepoTags, - Digest: img.Digest, - Created: img.Created, - Size: img.Size, + ID: img.ID(), + Name: img.Names(), + Digest: img.Digest(), + Created: img.Created(), + Size: size, } imagesOutput = append(imagesOutput, params) } @@ -217,7 +230,7 @@ func getImagesJSONOutput(runtime *libpod.Runtime, images []inspect.ImageResult) // generateImagesOutput generates the images based on the format provided -func generateImagesOutput(runtime *libpod.Runtime, images []inspect.ImageResult, opts imagesOptions) error { +func generateImagesOutput(runtime *libpod.Runtime, images []*image.Image, opts imagesOptions) error { if len(images) == 0 { return nil } @@ -253,35 +266,23 @@ func (i *imagesTemplateParams) HeaderMap() map[string]string { // CreateFilterFuncs returns an array of filter functions based on the user inputs // and is later used to filter images for output -func CreateFilterFuncs(r *libpod.Runtime, c *cli.Context, userInput string) ([]libpod.ImageResultFilter, error) { +func CreateFilterFuncs(r *libpod.Runtime, c *cli.Context, image *image.Image) ([]libpod.ImageResultFilter, error) { var filterFuncs []libpod.ImageResultFilter for _, filter := range c.StringSlice("filter") { splitFilter := strings.Split(filter, "=") switch splitFilter[0] { case "before": - before := r.NewImage(splitFilter[1]) - _, beforeID, _ := before.GetLocalImageName() - - if before.LocalName == "" { - return nil, errors.Errorf("unable to find image % in local stores", splitFilter[1]) - } - img, err := r.GetImage(beforeID) + before, err := r.ImageRuntime().NewFromLocal(splitFilter[1]) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to find image % in local stores", splitFilter[1]) } - filterFuncs = append(filterFuncs, libpod.ImageCreatedBefore(img.Created)) + filterFuncs = append(filterFuncs, libpod.ImageCreatedBefore(before.Created())) case "after": - after := r.NewImage(splitFilter[1]) - _, afterID, _ := after.GetLocalImageName() - - if after.LocalName == "" { - return nil, errors.Errorf("unable to find image % in local stores", splitFilter[1]) - } - img, err := r.GetImage(afterID) + after, err := r.ImageRuntime().NewFromLocal(splitFilter[1]) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to find image % in local stores", splitFilter[1]) } - filterFuncs = append(filterFuncs, libpod.ImageCreatedAfter(img.Created)) + filterFuncs = append(filterFuncs, libpod.ImageCreatedAfter(after.Created())) case "dangling": filterFuncs = append(filterFuncs, libpod.ImageDangling()) case "label": @@ -291,8 +292,8 @@ func CreateFilterFuncs(r *libpod.Runtime, c *cli.Context, userInput string) ([]l return nil, errors.Errorf("invalid filter %s ", splitFilter[0]) } } - if len(strings.TrimSpace(userInput)) != 0 { - filterFuncs = append(filterFuncs, libpod.OutputImageFilter(userInput)) + if image != nil { + filterFuncs = append(filterFuncs, libpod.OutputImageFilter(image)) } return filterFuncs, nil } diff --git a/libpod/image/image.go b/libpod/image/image.go index 5e69a0a98..15fc5174c 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -29,12 +29,16 @@ import ( // Image is the primary struct for dealing with images // It is still very much a work in progress type Image struct { + // Adding these two structs for now but will cull when we near + // completion of this library. inspect.ImageData + inspect.ImageResult InputName string Local bool //runtime *libpod.Runtime image *storage.Image imageruntime *Runtime + repotagsMap map[string][]string } // Runtime contains the store @@ -496,6 +500,28 @@ func (i *Image) History() ([]ociv1.History, []types.BlobInfo, error) { return oci.History, img.LayerInfos(), nil } +// Dangling returns a bool if the image is "dangling" +func (i *Image) Dangling() bool { + return len(i.Names()) == 0 +} + +// Labels returns the image's labels +func (i *Image) Labels() (map[string]string, error) { + sr, err := i.toStorageReference() + if err != nil { + return nil, err + } + ic, err := sr.NewImage(&types.SystemContext{}) + if err != nil { + return nil, err + } + imgInspect, err := ic.Inspect() + if err != nil { + return nil, err + } + return imgInspect.Labels, nil +} + // Import imports and image into the store and returns an image func Import(path, reference string, writer io.Writer, signingOptions SigningOptions, imageConfig ociv1.Image, runtime *Runtime) (*Image, error) { file := TarballTransport + ":" + path diff --git a/libpod/image/utils.go b/libpod/image/utils.go index 76ec349f9..c1b2aacde 100644 --- a/libpod/image/utils.go +++ b/libpod/image/utils.go @@ -90,3 +90,23 @@ func getPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error func hasTransport(image string) bool { return strings.Contains(image, "://") } + +// ReposToMap parses the specified repotags and returns a map with repositories +// as keys and the corresponding arrays of tags as values. +func ReposToMap(repotags []string) map[string][]string { + // map format is repo -> tag + repos := make(map[string][]string) + for _, repo := range repotags { + var repository, tag string + if len(repo) > 0 { + li := strings.LastIndex(repo, ":") + repository = repo[0:li] + tag = repo[li+1:] + } + repos[repository] = append(repos[repository], tag) + } + if len(repos) == 0 { + repos["<none>"] = []string{"<none>"} + } + return repos +} diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index a58626855..e3cb4e2c3 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -110,7 +110,7 @@ type imageDecomposeStruct struct { } // ImageResultFilter is a mock function for image filtering -type ImageResultFilter func(inspect.ImageResult) bool +type ImageResultFilter func(*image.Image) bool func (k *Image) assembleFqName() string { return fmt.Sprintf("%s/%s:%s", k.Registry, k.ImageName, k.Tag) @@ -983,8 +983,6 @@ func (r *Runtime) GetImages(params *ImageFilterParams, filters ...ImageFilter) ( if include { newImage := img - // TODO I dont think this is needed. Will verify along the way - //newImage.Names = []string{name} imagesFiltered = append(imagesFiltered, newImage) } } @@ -1184,98 +1182,11 @@ func getPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error return policyContext, nil } -// sizer knows its size. -type sizer interface { - Size() (int64, error) -} - -func imageSize(img types.ImageSource) *uint64 { - if s, ok := img.(sizer); ok { - if sum, err := s.Size(); err == nil { - usum := uint64(sum) - return &usum - } - } - return nil -} - -// ReposToMap parses the specified repotags and returns a map with repositories -// as keys and the corresponding arrays of tags as values. -func ReposToMap(repotags []string) map[string][]string { - // map format is repo -> tag - repos := make(map[string][]string) - for _, repo := range repotags { - var repository, tag string - if len(repo) > 0 { - li := strings.LastIndex(repo, ":") - repository = repo[0:li] - tag = repo[li+1:] - } - repos[repository] = append(repos[repository], tag) - } - if len(repos) == 0 { - repos["<none>"] = []string{"<none>"} - } - return repos -} - -// GetImageResults gets the images for podman images and returns them as -// an array of ImageResults -func (r *Runtime) GetImageResults() ([]inspect.ImageResult, error) { - var results []inspect.ImageResult - - images, err := r.store.Images() - if err != nil { - return nil, err - } - for _, image := range images { - storeRef, err := is.Transport.ParseStoreReference(r.store, image.ID) - if err != nil { - return nil, err - } - systemContext := &types.SystemContext{} - img, err := storeRef.NewImageSource(systemContext) - if err != nil { - return nil, err - } - ic, err := storeRef.NewImage(&types.SystemContext{}) - if err != nil { - return nil, err - } - imgInspect, err := ic.Inspect() - if err != nil { - return nil, err - } - dangling := false - if len(image.Names) == 0 { - dangling = true - } - - for repo, tags := range ReposToMap(image.Names) { - // use the first pair as the image's default repo and tag - results = append(results, inspect.ImageResult{ - ID: image.ID, - Repository: repo, - RepoTags: image.Names, - Tag: tags[0], - Size: imageSize(img), - Digest: image.Digest, - Created: image.Created, - Labels: imgInspect.Labels, - Dangling: dangling, - }) - break - } - - } - return results, nil -} - // ImageCreatedBefore allows you to filter on images created before // the given time.Time func ImageCreatedBefore(createTime time.Time) ImageResultFilter { - return func(i inspect.ImageResult) bool { - if i.Created.Before(createTime) { + return func(i *image.Image) bool { + if i.Created().Before(createTime) { return true } return false @@ -1285,8 +1196,8 @@ func ImageCreatedBefore(createTime time.Time) ImageResultFilter { // ImageCreatedAfter allows you to filter on images created after // the given time.Time func ImageCreatedAfter(createTime time.Time) ImageResultFilter { - return func(i inspect.ImageResult) bool { - if i.Created.After(createTime) { + return func(i *image.Image) bool { + if i.Created().After(createTime) { return true } return false @@ -1295,8 +1206,8 @@ func ImageCreatedAfter(createTime time.Time) ImageResultFilter { // ImageDangling allows you to filter images for dangling images func ImageDangling() ImageResultFilter { - return func(i inspect.ImageResult) bool { - if i.Dangling { + return func(i *image.Image) bool { + if i.Dangling() { return true } return false @@ -1306,51 +1217,34 @@ func ImageDangling() ImageResultFilter { // ImageLabel allows you to filter by images labels key and/or value func ImageLabel(labelfilter string) ImageResultFilter { // We need to handle both label=key and label=key=value - return func(i inspect.ImageResult) bool { + return func(i *image.Image) bool { var value string splitFilter := strings.Split(labelfilter, "=") key := splitFilter[0] if len(splitFilter) > 1 { value = splitFilter[1] } - for labelKey, labelValue := range i.Labels { - // handles label=key - if key == labelKey && len(strings.TrimSpace(value)) == 0 { - return true - } - //handles label=key=value - if key == labelKey && value == labelValue { - return true - } + labels, err := i.Labels() + if err != nil { + return false } - return false + if len(strings.TrimSpace(labels[key])) > 0 && len(strings.TrimSpace(value)) == 0 { + return true + } + return labels[key] == value } } // OutputImageFilter allows you to filter by an a specific image name -func OutputImageFilter(name string) ImageResultFilter { - return func(i inspect.ImageResult) bool { - li := strings.LastIndex(name, ":") - var repository, tag string - if li < 0 { - repository = name - } else { - repository = name[0:li] - tag = name[li+1:] - } - if repository == i.Repository && len(strings.TrimSpace(tag)) == 0 { - return true - } - if repository == i.Repository && tag == i.Tag { - return true - } - return false +func OutputImageFilter(userImage *image.Image) ImageResultFilter { + return func(i *image.Image) bool { + return userImage.ID() == i.ID() } } // FilterImages filters images using a set of predefined fitler funcs -func FilterImages(images []inspect.ImageResult, filters []ImageResultFilter) []inspect.ImageResult { - var filteredImages []inspect.ImageResult +func FilterImages(images []*image.Image, filters []ImageResultFilter) []*image.Image { + var filteredImages []*image.Image for _, image := range images { include := true for _, filter := range filters { |