Merge pull request #5588 from baude/apiv2commitfix

apiv2 container commit for libpod
This commit is contained in:
OpenShift Merge Robot
2020-03-23 21:20:07 +01:00
committed by GitHub
5 changed files with 156 additions and 4 deletions

View File

@ -10,12 +10,15 @@ import (
"strconv"
"strings"
"github.com/containers/buildah"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
image2 "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/util"
@ -416,3 +419,84 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, res)
}
func CommitContainer(w http.ResponseWriter, r *http.Request) {
var (
destImage string
mimeType string
)
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
query := struct {
Author string `schema:"author"`
Changes []string `schema:"changes"`
Comment string `schema:"comment"`
Container string `schema:"container"`
Format string `schema:"format"`
Pause bool `schema:"pause"`
Repo string `schema:"repo"`
Tag string `schema:"tag"`
}{
Format: "oci",
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
rtc, err := runtime.GetConfig()
if err != nil {
utils.Error(w, "failed to get runtime config", http.StatusInternalServerError, errors.Wrap(err, "failed to get runtime config"))
return
}
sc := image2.GetSystemContext(rtc.SignaturePolicyPath, "", false)
tag := "latest"
options := libpod.ContainerCommitOptions{
Pause: true,
}
switch query.Format {
case "oci":
mimeType = buildah.OCIv1ImageManifest
if len(query.Comment) > 0 {
utils.InternalServerError(w, errors.New("messages are only compatible with the docker image format (-f docker)"))
return
}
case "docker":
mimeType = manifest.DockerV2Schema2MediaType
default:
utils.InternalServerError(w, errors.Errorf("unrecognized image format %q", query.Format))
return
}
options.CommitOptions = buildah.CommitOptions{
SignaturePolicyPath: rtc.SignaturePolicyPath,
ReportWriter: os.Stderr,
SystemContext: sc,
PreferredManifestType: mimeType,
}
if len(query.Tag) > 0 {
tag = query.Tag
}
options.Message = query.Comment
options.Author = query.Author
options.Pause = query.Pause
options.Changes = query.Changes
ctr, err := runtime.LookupContainer(query.Container)
if err != nil {
utils.Error(w, "failed to lookup container", http.StatusNotFound, err)
return
}
// I know mitr hates this ... but doing for now
if len(query.Repo) > 1 {
destImage = fmt.Sprintf("%s:%s", query.Repo, tag)
}
commitImage, err := ctr.Commit(r.Context(), destImage, options)
if err != nil && !strings.Contains(err.Error(), "is not running") {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure"))
return
}
utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: commitImage.ID()}) // nolint
}

View File

@ -978,6 +978,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// name: container
// type: string
// description: the name or ID of a container
// required: true
// - in: query
// name: repo
// type: string
@ -1000,8 +1001,14 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: pause the container before committing it
// - in: query
// name: changes
// description: instructions to apply while committing in Dockerfile format (i.e. "CMD=/bin/foo")
// type: array
// items:
// type: string
// - in: query
// name: format
// type: string
// description: instructions to apply while committing in Dockerfile format
// description: format of the image manifest and metadata (default "oci")
// produces:
// - application/json
// responses:
@ -1011,6 +1018,6 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// $ref: '#/responses/NoSuchImage'
// 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/commit"), s.APIHandler(compat.CommitContainer)).Methods(http.MethodPost)
r.Handle(VersionedPath("/libpod/commit"), s.APIHandler(libpod.CommitContainer)).Methods(http.MethodPost)
return nil
}

View File

@ -0,0 +1,49 @@
package containers
import (
"context"
"net/http"
"net/url"
"strconv"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/bindings"
)
// Commit creates a container image from a container. The container is defined by nameOrId. Use
// the CommitOptions for finer grain control on characteristics of the resulting image.
func Commit(ctx context.Context, nameOrId string, options CommitOptions) (handlers.IDResponse, error) {
id := handlers.IDResponse{}
conn, err := bindings.GetClient(ctx)
if err != nil {
return id, err
}
params := url.Values{}
params.Set("container", nameOrId)
if options.Author != nil {
params.Set("author", *options.Author)
}
for _, change := range options.Changes {
params.Set("changes", change)
}
if options.Comment != nil {
params.Set("comment", *options.Comment)
}
if options.Format != nil {
params.Set("format", *options.Format)
}
if options.Pause != nil {
params.Set("pause", strconv.FormatBool(*options.Pause))
}
if options.Repo != nil {
params.Set("repo", *options.Repo)
}
if options.Tag != nil {
params.Set("tag", *options.Tag)
}
response, err := conn.DoRequest(nil, http.MethodPost, "/commit", params)
if err != nil {
return id, err
}
return id, response.Process(&id)
}

View File

@ -11,3 +11,16 @@ type LogOptions struct {
Timestamps *bool
Until *string
}
// CommitOptions describe details about the resulting commited
// image as defined by repo and tag. None of these options
// are required.
type CommitOptions struct {
Author *string
Changes []string
Comment *string
Format *string
Pause *bool
Repo *string
Tag *string
}

View File

@ -80,8 +80,7 @@ var _ = Describe("Podman pods", func() {
// The test validates the list pod endpoint with passing filters as the params.
It("List pods with filters", func() {
var (
newpod2 string = "newpod2"
trueFlag = true
newpod2 string = "newpod2"
)
bt.Podcreate(&newpod2)
_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)