mirror of
https://github.com/containers/podman.git
synced 2025-06-23 18:59:30 +08:00
Merge pull request #5588 from baude/apiv2commitfix
apiv2 container commit for libpod
This commit is contained in:
@ -10,12 +10,15 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/buildah"
|
||||||
"github.com/containers/image/v5/docker"
|
"github.com/containers/image/v5/docker"
|
||||||
"github.com/containers/image/v5/docker/reference"
|
"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/transports/alltransports"
|
||||||
"github.com/containers/image/v5/types"
|
"github.com/containers/image/v5/types"
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
"github.com/containers/libpod/libpod/image"
|
"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"
|
||||||
"github.com/containers/libpod/pkg/api/handlers/utils"
|
"github.com/containers/libpod/pkg/api/handlers/utils"
|
||||||
"github.com/containers/libpod/pkg/util"
|
"github.com/containers/libpod/pkg/util"
|
||||||
@ -416,3 +419,84 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
utils.WriteResponse(w, http.StatusOK, res)
|
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
|
||||||
|
}
|
||||||
|
@ -978,6 +978,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
|
|||||||
// name: container
|
// name: container
|
||||||
// type: string
|
// type: string
|
||||||
// description: the name or ID of a container
|
// description: the name or ID of a container
|
||||||
|
// required: true
|
||||||
// - in: query
|
// - in: query
|
||||||
// name: repo
|
// name: repo
|
||||||
// type: string
|
// type: string
|
||||||
@ -1000,8 +1001,14 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
|
|||||||
// description: pause the container before committing it
|
// description: pause the container before committing it
|
||||||
// - in: query
|
// - in: query
|
||||||
// name: changes
|
// 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
|
// type: string
|
||||||
// description: instructions to apply while committing in Dockerfile format
|
// description: format of the image manifest and metadata (default "oci")
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// responses:
|
// responses:
|
||||||
@ -1011,6 +1018,6 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
|
|||||||
// $ref: '#/responses/NoSuchImage'
|
// $ref: '#/responses/NoSuchImage'
|
||||||
// 500:
|
// 500:
|
||||||
// $ref: '#/responses/InternalError'
|
// $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
|
return nil
|
||||||
}
|
}
|
||||||
|
49
pkg/bindings/containers/commit.go
Normal file
49
pkg/bindings/containers/commit.go
Normal 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)
|
||||||
|
}
|
@ -11,3 +11,16 @@ type LogOptions struct {
|
|||||||
Timestamps *bool
|
Timestamps *bool
|
||||||
Until *string
|
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
|
||||||
|
}
|
||||||
|
@ -80,8 +80,7 @@ var _ = Describe("Podman pods", func() {
|
|||||||
// The test validates the list pod endpoint with passing filters as the params.
|
// The test validates the list pod endpoint with passing filters as the params.
|
||||||
It("List pods with filters", func() {
|
It("List pods with filters", func() {
|
||||||
var (
|
var (
|
||||||
newpod2 string = "newpod2"
|
newpod2 string = "newpod2"
|
||||||
trueFlag = true
|
|
||||||
)
|
)
|
||||||
bt.Podcreate(&newpod2)
|
bt.Podcreate(&newpod2)
|
||||||
_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)
|
_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)
|
||||||
|
Reference in New Issue
Block a user