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/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
}

View File

@ -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

View File

@ -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
}

View File

@ -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 {