forked from containers/podman
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request containers#5449 from baude/manifests
apiv2 addition of manifests
- Loading branch information
Showing
17 changed files
with
2,073 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package libpod | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
|
||
"github.com/containers/buildah/manifests" | ||
copy2 "github.com/containers/image/v5/copy" | ||
"github.com/containers/image/v5/transports/alltransports" | ||
"github.com/containers/libpod/libpod" | ||
"github.com/containers/libpod/libpod/image" | ||
"github.com/containers/libpod/pkg/api/handlers" | ||
"github.com/containers/libpod/pkg/api/handlers/utils" | ||
"github.com/gorilla/schema" | ||
"github.com/opencontainers/go-digest" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
func ManifestCreate(w http.ResponseWriter, r *http.Request) { | ||
runtime := r.Context().Value("runtime").(*libpod.Runtime) | ||
decoder := r.Context().Value("decoder").(*schema.Decoder) | ||
query := struct { | ||
Name []string `schema:"name"` | ||
Image []string `schema:"image"` | ||
All bool `schema:"all"` | ||
}{ | ||
// Add defaults here once needed. | ||
} | ||
if err := decoder.Decode(&query, r.URL.Query()); err != nil { | ||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, | ||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) | ||
return | ||
} | ||
rtc, err := runtime.GetConfig() | ||
if err != nil { | ||
utils.InternalServerError(w, err) | ||
return | ||
} | ||
sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false) | ||
manID, err := image.CreateManifestList(runtime.ImageRuntime(), *sc, query.Name, query.Image, query.All) | ||
if err != nil { | ||
utils.InternalServerError(w, err) | ||
return | ||
} | ||
utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: manID}) | ||
} | ||
|
||
func ManifestInspect(w http.ResponseWriter, r *http.Request) { | ||
runtime := r.Context().Value("runtime").(*libpod.Runtime) | ||
name := utils.GetName(r) | ||
newImage, err := runtime.ImageRuntime().NewFromLocal(name) | ||
if err != nil { | ||
utils.ImageNotFound(w, name, err) | ||
return | ||
} | ||
data, err := newImage.InspectManifest() | ||
if err != nil { | ||
utils.InternalServerError(w, err) | ||
return | ||
} | ||
utils.WriteResponse(w, http.StatusOK, data) | ||
} | ||
|
||
func ManifestAdd(w http.ResponseWriter, r *http.Request) { | ||
runtime := r.Context().Value("runtime").(*libpod.Runtime) | ||
var manifestInput image.ManifestAddOpts | ||
if err := json.NewDecoder(r.Body).Decode(&manifestInput); err != nil { | ||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()")) | ||
return | ||
} | ||
name := utils.GetName(r) | ||
newImage, err := runtime.ImageRuntime().NewFromLocal(name) | ||
if err != nil { | ||
utils.ImageNotFound(w, name, err) | ||
return | ||
} | ||
rtc, err := runtime.GetConfig() | ||
if err != nil { | ||
utils.InternalServerError(w, err) | ||
return | ||
} | ||
sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false) | ||
newID, err := newImage.AddManifest(*sc, manifestInput) | ||
if err != nil { | ||
utils.InternalServerError(w, err) | ||
return | ||
} | ||
utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: newID}) | ||
} | ||
|
||
func ManifestRemove(w http.ResponseWriter, r *http.Request) { | ||
runtime := r.Context().Value("runtime").(*libpod.Runtime) | ||
decoder := r.Context().Value("decoder").(*schema.Decoder) | ||
query := struct { | ||
Digest string `schema:"digest"` | ||
}{ | ||
// Add defaults here once needed. | ||
} | ||
name := utils.GetName(r) | ||
if err := decoder.Decode(&query, r.URL.Query()); err != nil { | ||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, | ||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) | ||
return | ||
} | ||
newImage, err := runtime.ImageRuntime().NewFromLocal(name) | ||
if err != nil { | ||
utils.ImageNotFound(w, name, err) | ||
return | ||
} | ||
d, err := digest.Parse(query.Digest) | ||
if err != nil { | ||
utils.Error(w, "invalid digest", http.StatusBadRequest, err) | ||
return | ||
} | ||
newID, err := newImage.RemoveManifest(d) | ||
if err != nil { | ||
utils.InternalServerError(w, err) | ||
return | ||
} | ||
utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: newID}) | ||
} | ||
func ManifestPush(w http.ResponseWriter, r *http.Request) { | ||
runtime := r.Context().Value("runtime").(*libpod.Runtime) | ||
decoder := r.Context().Value("decoder").(*schema.Decoder) | ||
query := struct { | ||
All bool `schema:"all"` | ||
Destination string `schema:"destination"` | ||
}{ | ||
// Add defaults here once needed. | ||
} | ||
if err := decoder.Decode(&query, r.URL.Query()); err != nil { | ||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, | ||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) | ||
return | ||
} | ||
name := utils.GetName(r) | ||
newImage, err := runtime.ImageRuntime().NewFromLocal(name) | ||
if err != nil { | ||
utils.ImageNotFound(w, name, err) | ||
return | ||
} | ||
dest, err := alltransports.ParseImageName(query.Destination) | ||
if err != nil { | ||
utils.Error(w, "invalid destination parameter", http.StatusBadRequest, errors.Errorf("invalid destination parameter %q", query.Destination)) | ||
return | ||
} | ||
rtc, err := runtime.GetConfig() | ||
if err != nil { | ||
utils.InternalServerError(w, err) | ||
return | ||
} | ||
sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false) | ||
opts := manifests.PushOptions{ | ||
ImageListSelection: copy2.CopySpecificImages, | ||
SystemContext: sc, | ||
} | ||
if query.All { | ||
opts.ImageListSelection = copy2.CopyAllImages | ||
} | ||
newD, err := newImage.PushManifest(dest, opts) | ||
if err != nil { | ||
utils.InternalServerError(w, err) | ||
return | ||
} | ||
utils.WriteResponse(w, http.StatusOK, newD.String()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,17 @@ | ||
package libpod | ||
|
||
import "github.com/containers/image/v5/manifest" | ||
|
||
// List Containers | ||
// swagger:response ListContainers | ||
type swagInspectPodResponse struct { | ||
// in:body | ||
Body []ListContainer | ||
} | ||
|
||
// Inspect Manifest | ||
// swagger:response InspectManifest | ||
type swagInspectManifestResponse struct { | ||
// in:body | ||
Body manifest.List | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.