Migrate podman images to image library

Signed-off-by: baude <bbaude@redhat.com>

Closes: #523
Approved by: mheon
This commit is contained in:
baude
2018-03-20 10:21:13 -05:00
committed by Atomic Bot
parent 64416f14be
commit 3428de0672
4 changed files with 111 additions and 170 deletions

View File

@ -10,7 +10,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/projectatomic/libpod/cmd/podman/formats" "github.com/projectatomic/libpod/cmd/podman/formats"
"github.com/projectatomic/libpod/libpod" "github.com/projectatomic/libpod/libpod"
"github.com/projectatomic/libpod/pkg/inspect" "github.com/projectatomic/libpod/libpod/image"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -81,6 +81,10 @@ var (
) )
func imagesCmd(c *cli.Context) error { func imagesCmd(c *cli.Context) error {
var (
filterFuncs []libpod.ImageResultFilter
newImage *image.Image
)
if err := validateFlags(c, imagesFlags); err != nil { if err := validateFlags(c, imagesFlags); err != nil {
return err return err
} }
@ -90,18 +94,19 @@ func imagesCmd(c *cli.Context) error {
return errors.Wrapf(err, "Could not get runtime") return errors.Wrapf(err, "Could not get runtime")
} }
defer runtime.Shutdown(false) defer runtime.Shutdown(false)
var filterFuncs []libpod.ImageResultFilter
var imageInput string
if len(c.Args()) == 1 { 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 { if len(c.Args()) > 1 {
return errors.New("'podman images' requires at most 1 argument") return errors.New("'podman images' requires at most 1 argument")
} }
if len(c.StringSlice("filter")) > 0 || len(strings.TrimSpace(imageInput)) != 0 { if len(c.StringSlice("filter")) > 0 || newImage != nil {
filterFuncs, err = CreateFilterFuncs(runtime, c, imageInput) filterFuncs, err = CreateFilterFuncs(runtime, c, newImage)
if err != nil { if err != nil {
return err return err
} }
@ -123,14 +128,14 @@ func imagesCmd(c *cli.Context) error {
children to the image once built. until buildah supports caching builds, children to the image once built. until buildah supports caching builds,
it will not generate these intermediate images. it will not generate these intermediate images.
*/ */
images, err := runtime.GetImageResults() images, err := runtime.ImageRuntime().GetImages()
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to get images") return errors.Wrapf(err, "unable to get images")
} }
var filteredImages []inspect.ImageResult var filteredImages []*image.Image
// filter the images // 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) filteredImages = libpod.FilterImages(images, filterFuncs)
} else { } else {
filteredImages = images filteredImages = images
@ -174,24 +179,28 @@ func imagesToGeneric(templParams []imagesTemplateParams, JSONParams []imagesJSON
} }
// getImagesTemplateOutput returns the images information to be printed in human readable format // 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 { for _, img := range images {
createdTime := img.Created createdTime := img.Created()
imageID := "sha256:" + img.ID imageID := "sha256:" + img.ID()
if !opts.noTrunc { if !opts.noTrunc {
imageID = shortID(img.ID) imageID = shortID(img.ID())
} }
// get all specified repo:tag pairs and print them separately // 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 { for _, tag := range tags {
size, err := img.Size()
if err != nil {
size = nil
}
params := imagesTemplateParams{ params := imagesTemplateParams{
Repository: repo, Repository: repo,
Tag: tag, Tag: tag,
ID: imageID, ID: imageID,
Digest: img.Digest, Digest: img.Digest(),
Created: units.HumanDuration(time.Since((createdTime))) + " ago", Created: units.HumanDuration(time.Since((createdTime))) + " ago",
Size: units.HumanSizeWithPrecision(float64(*img.Size), 3), Size: units.HumanSizeWithPrecision(float64(*size), 3),
} }
imagesOutput = append(imagesOutput, params) 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 // 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 { for _, img := range images {
size, err := img.Size()
if err != nil {
size = nil
}
params := imagesJSONParams{ params := imagesJSONParams{
ID: img.ID, ID: img.ID(),
Name: img.RepoTags, Name: img.Names(),
Digest: img.Digest, Digest: img.Digest(),
Created: img.Created, Created: img.Created(),
Size: img.Size, Size: size,
} }
imagesOutput = append(imagesOutput, params) 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 // 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 { if len(images) == 0 {
return nil 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 // CreateFilterFuncs returns an array of filter functions based on the user inputs
// and is later used to filter images for output // 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 var filterFuncs []libpod.ImageResultFilter
for _, filter := range c.StringSlice("filter") { for _, filter := range c.StringSlice("filter") {
splitFilter := strings.Split(filter, "=") splitFilter := strings.Split(filter, "=")
switch splitFilter[0] { switch splitFilter[0] {
case "before": case "before":
before := r.NewImage(splitFilter[1]) before, err := r.ImageRuntime().NewFromLocal(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)
if err != nil { 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": case "after":
after := r.NewImage(splitFilter[1]) after, err := r.ImageRuntime().NewFromLocal(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)
if err != nil { 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": case "dangling":
filterFuncs = append(filterFuncs, libpod.ImageDangling()) filterFuncs = append(filterFuncs, libpod.ImageDangling())
case "label": 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]) return nil, errors.Errorf("invalid filter %s ", splitFilter[0])
} }
} }
if len(strings.TrimSpace(userInput)) != 0 { if image != nil {
filterFuncs = append(filterFuncs, libpod.OutputImageFilter(userInput)) filterFuncs = append(filterFuncs, libpod.OutputImageFilter(image))
} }
return filterFuncs, nil return filterFuncs, nil
} }

View File

@ -29,12 +29,16 @@ import (
// Image is the primary struct for dealing with images // Image is the primary struct for dealing with images
// It is still very much a work in progress // It is still very much a work in progress
type Image struct { type Image struct {
// Adding these two structs for now but will cull when we near
// completion of this library.
inspect.ImageData inspect.ImageData
inspect.ImageResult
InputName string InputName string
Local bool Local bool
//runtime *libpod.Runtime //runtime *libpod.Runtime
image *storage.Image image *storage.Image
imageruntime *Runtime imageruntime *Runtime
repotagsMap map[string][]string
} }
// Runtime contains the store // Runtime contains the store
@ -496,6 +500,28 @@ func (i *Image) History() ([]ociv1.History, []types.BlobInfo, error) {
return oci.History, img.LayerInfos(), nil 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 // 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) { func Import(path, reference string, writer io.Writer, signingOptions SigningOptions, imageConfig ociv1.Image, runtime *Runtime) (*Image, error) {
file := TarballTransport + ":" + path file := TarballTransport + ":" + path

View File

@ -90,3 +90,23 @@ func getPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error
func hasTransport(image string) bool { func hasTransport(image string) bool {
return strings.Contains(image, "://") 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
}

View File

@ -110,7 +110,7 @@ type imageDecomposeStruct struct {
} }
// ImageResultFilter is a mock function for image filtering // 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 { func (k *Image) assembleFqName() string {
return fmt.Sprintf("%s/%s:%s", k.Registry, k.ImageName, k.Tag) 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 { if include {
newImage := img newImage := img
// TODO I dont think this is needed. Will verify along the way
//newImage.Names = []string{name}
imagesFiltered = append(imagesFiltered, newImage) imagesFiltered = append(imagesFiltered, newImage)
} }
} }
@ -1184,98 +1182,11 @@ func getPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error
return policyContext, nil 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 // ImageCreatedBefore allows you to filter on images created before
// the given time.Time // the given time.Time
func ImageCreatedBefore(createTime time.Time) ImageResultFilter { func ImageCreatedBefore(createTime time.Time) ImageResultFilter {
return func(i inspect.ImageResult) bool { return func(i *image.Image) bool {
if i.Created.Before(createTime) { if i.Created().Before(createTime) {
return true return true
} }
return false return false
@ -1285,8 +1196,8 @@ func ImageCreatedBefore(createTime time.Time) ImageResultFilter {
// ImageCreatedAfter allows you to filter on images created after // ImageCreatedAfter allows you to filter on images created after
// the given time.Time // the given time.Time
func ImageCreatedAfter(createTime time.Time) ImageResultFilter { func ImageCreatedAfter(createTime time.Time) ImageResultFilter {
return func(i inspect.ImageResult) bool { return func(i *image.Image) bool {
if i.Created.After(createTime) { if i.Created().After(createTime) {
return true return true
} }
return false return false
@ -1295,8 +1206,8 @@ func ImageCreatedAfter(createTime time.Time) ImageResultFilter {
// ImageDangling allows you to filter images for dangling images // ImageDangling allows you to filter images for dangling images
func ImageDangling() ImageResultFilter { func ImageDangling() ImageResultFilter {
return func(i inspect.ImageResult) bool { return func(i *image.Image) bool {
if i.Dangling { if i.Dangling() {
return true return true
} }
return false return false
@ -1306,51 +1217,34 @@ func ImageDangling() ImageResultFilter {
// ImageLabel allows you to filter by images labels key and/or value // ImageLabel allows you to filter by images labels key and/or value
func ImageLabel(labelfilter string) ImageResultFilter { func ImageLabel(labelfilter string) ImageResultFilter {
// We need to handle both label=key and label=key=value // 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 var value string
splitFilter := strings.Split(labelfilter, "=") splitFilter := strings.Split(labelfilter, "=")
key := splitFilter[0] key := splitFilter[0]
if len(splitFilter) > 1 { if len(splitFilter) > 1 {
value = splitFilter[1] value = splitFilter[1]
} }
for labelKey, labelValue := range i.Labels { labels, err := i.Labels()
// handles label=key if err != nil {
if key == labelKey && len(strings.TrimSpace(value)) == 0 {
return true
}
//handles label=key=value
if key == labelKey && value == labelValue {
return true
}
}
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 // OutputImageFilter allows you to filter by an a specific image name
func OutputImageFilter(name string) ImageResultFilter { func OutputImageFilter(userImage *image.Image) ImageResultFilter {
return func(i inspect.ImageResult) bool { return func(i *image.Image) bool {
li := strings.LastIndex(name, ":") return userImage.ID() == i.ID()
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
} }
} }
// FilterImages filters images using a set of predefined fitler funcs // FilterImages filters images using a set of predefined fitler funcs
func FilterImages(images []inspect.ImageResult, filters []ImageResultFilter) []inspect.ImageResult { func FilterImages(images []*image.Image, filters []ImageResultFilter) []*image.Image {
var filteredImages []inspect.ImageResult var filteredImages []*image.Image
for _, image := range images { for _, image := range images {
include := true include := true
for _, filter := range filters { for _, filter := range filters {