From abbbeacd68b4d4973a55a8d7263bd0a27f5c4e8e Mon Sep 17 00:00:00 2001 From: Brent Baude Date: Wed, 4 Mar 2020 10:14:07 -0600 Subject: apiv2 addition of manifests add endpoints for create, add, remove, inspect, and push. this allows manifests to be managed through the restful interfaces. also added go-bindings and tests Signed-off-by: Brent Baude --- libpod/image/manifests.go | 154 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 libpod/image/manifests.go (limited to 'libpod/image/manifests.go') diff --git a/libpod/image/manifests.go b/libpod/image/manifests.go new file mode 100644 index 000000000..9dbeb4cc5 --- /dev/null +++ b/libpod/image/manifests.go @@ -0,0 +1,154 @@ +package image + +import ( + "context" + + "github.com/containers/buildah/manifests" + "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/transports/alltransports" + "github.com/containers/image/v5/types" + "github.com/opencontainers/go-digest" + "github.com/pkg/errors" +) + +// Options for adding a manifest +// swagger:model ManifestAddOpts +type ManifestAddOpts struct { + All bool `json:"all"` + Annotation map[string]string `json:"annotation"` + Arch string `json:"arch"` + Features []string `json:"features"` + Images []string `json:"images"` + OSVersion string `json:"os_version"` + Variant string `json:"variant"` +} + +// InspectManifest returns a dockerized version of the manifest list +func (i *Image) InspectManifest() (*manifest.Schema2List, error) { + list, err := i.getManifestList() + if err != nil { + return nil, err + } + return list.Docker(), nil +} + +// RemoveManifest removes the given digest from the manifest list. +func (i *Image) RemoveManifest(d digest.Digest) (string, error) { + list, err := i.getManifestList() + if err != nil { + return "", err + } + if err := list.Remove(d); err != nil { + return "", err + } + return list.SaveToImage(i.imageruntime.store, i.ID(), nil, "") +} + +// getManifestList is a helper to obtain a manifest list +func (i *Image) getManifestList() (manifests.List, error) { + _, list, err := manifests.LoadFromImage(i.imageruntime.store, i.ID()) + return list, err +} + +// CreateManifestList creates a new manifest list and can optionally add given images +// to the list +func CreateManifestList(rt *Runtime, systemContext types.SystemContext, names []string, imgs []string, all bool) (string, error) { + list := manifests.Create() + opts := ManifestAddOpts{Images: names, All: all} + for _, img := range imgs { + var ref types.ImageReference + newImage, err := rt.NewFromLocal(img) + if err == nil { + ir, err := newImage.toImageRef(context.Background()) + if err != nil { + return "", err + } + if ir == nil { + return "", errors.New("unable to convert image to ImageReference") + } + ref = ir.Reference() + } else { + ref, err = alltransports.ParseImageName(img) + if err != nil { + return "", err + } + } + list, err = addManifestToList(ref, list, systemContext, opts) + if err != nil { + return "", err + } + } + return list.SaveToImage(rt.store, "", names, manifest.DockerV2ListMediaType) +} + +func addManifestToList(ref types.ImageReference, list manifests.List, systemContext types.SystemContext, opts ManifestAddOpts) (manifests.List, error) { + d, err := list.Add(context.Background(), &systemContext, ref, opts.All) + if err != nil { + return nil, err + } + if len(opts.OSVersion) > 0 { + if err := list.SetOSVersion(d, opts.OSVersion); err != nil { + return nil, err + } + } + if len(opts.Features) > 0 { + if err := list.SetFeatures(d, opts.Features); err != nil { + return nil, err + } + } + if len(opts.Arch) > 0 { + if err := list.SetArchitecture(d, opts.Arch); err != nil { + return nil, err + } + } + if len(opts.Variant) > 0 { + if err := list.SetVariant(d, opts.Variant); err != nil { + return nil, err + } + } + if len(opts.Annotation) > 0 { + if err := list.SetAnnotations(&d, opts.Annotation); err != nil { + return nil, err + } + } + return list, err +} + +// AddManifest adds a manifest to a given manifest list. +func (i *Image) AddManifest(systemContext types.SystemContext, opts ManifestAddOpts) (string, error) { + var ( + ref types.ImageReference + ) + newImage, err := i.imageruntime.NewFromLocal(opts.Images[0]) + if err == nil { + ir, err := newImage.toImageRef(context.Background()) + if err != nil { + return "", err + } + ref = ir.Reference() + } else { + ref, err = alltransports.ParseImageName(opts.Images[0]) + if err != nil { + return "", err + } + } + list, err := i.getManifestList() + if err != nil { + return "", err + } + list, err = addManifestToList(ref, list, systemContext, opts) + if err != nil { + return "", err + } + return list.SaveToImage(i.imageruntime.store, i.ID(), nil, "") +} + +// PushManifest pushes a manifest to a destination +func (i *Image) PushManifest(dest types.ImageReference, opts manifests.PushOptions) (digest.Digest, error) { + list, err := i.getManifestList() + if err != nil { + return "", err + } + _, d, err := list.Push(context.Background(), dest, opts) + return d, err +} -- cgit v1.2.3-54-g00ecf