mirror of
https://github.com/containers/podman.git
synced 2025-06-02 10:46:09 +08:00
Migrate podman images to image library
Signed-off-by: baude <bbaude@redhat.com> Closes: #523 Approved by: mheon
This commit is contained in:
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user