summaryrefslogtreecommitdiff
path: root/pkg/api/handlers/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api/handlers/libpod')
-rw-r--r--pkg/api/handlers/libpod/containers.go41
-rw-r--r--pkg/api/handlers/libpod/containers_create.go5
-rw-r--r--pkg/api/handlers/libpod/generate.go62
-rw-r--r--pkg/api/handlers/libpod/images.go6
-rw-r--r--pkg/api/handlers/libpod/images_pull.go31
-rw-r--r--pkg/api/handlers/libpod/images_push.go4
-rw-r--r--pkg/api/handlers/libpod/kube.go8
-rw-r--r--pkg/api/handlers/libpod/manifests.go77
-rw-r--r--pkg/api/handlers/libpod/pods.go12
9 files changed, 177 insertions, 69 deletions
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 5d85d4009..a76e3d988 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -1,6 +1,7 @@
package libpod
import (
+ "encoding/json"
"errors"
"fmt"
"io/ioutil"
@@ -10,6 +11,7 @@ import (
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/api/handlers"
"github.com/containers/podman/v4/pkg/api/handlers/compat"
"github.com/containers/podman/v4/pkg/api/handlers/utils"
api "github.com/containers/podman/v4/pkg/api/types"
@@ -17,6 +19,7 @@ import (
"github.com/containers/podman/v4/pkg/domain/infra/abi"
"github.com/containers/podman/v4/pkg/util"
"github.com/gorilla/schema"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
)
@@ -263,16 +266,16 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
+ if len(reports) != 1 {
+ utils.InternalServerError(w, fmt.Errorf("expected 1 restore report but got %d", len(reports)))
+ return
+ }
+ if reports[0].Err != nil {
+ utils.InternalServerError(w, reports[0].Err)
+ return
+ }
if !query.Export {
- if len(reports) != 1 {
- utils.InternalServerError(w, fmt.Errorf("expected 1 restore report but got %d", len(reports)))
- return
- }
- if reports[0].Err != nil {
- utils.InternalServerError(w, reports[0].Err)
- return
- }
utils.WriteResponse(w, http.StatusOK, reports[0])
return
}
@@ -391,6 +394,28 @@ func InitContainer(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusNoContent, "")
}
+func UpdateContainer(w http.ResponseWriter, r *http.Request) {
+ name := utils.GetName(r)
+ runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
+ ctr, err := runtime.LookupContainer(name)
+ if err != nil {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+
+ options := &handlers.UpdateEntities{Resources: &specs.LinuxResources{}}
+ if err := json.NewDecoder(r.Body).Decode(&options.Resources); err != nil {
+ utils.Error(w, http.StatusInternalServerError, fmt.Errorf("decode(): %w", err))
+ return
+ }
+ err = ctr.Update(options.Resources)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusCreated, ctr.ID())
+}
+
func ShouldRestart(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
// Now use the ABI implementation to prevent us from having duplicate
diff --git a/pkg/api/handlers/libpod/containers_create.go b/pkg/api/handlers/libpod/containers_create.go
index 1307c267a..429f45f91 100644
--- a/pkg/api/handlers/libpod/containers_create.go
+++ b/pkg/api/handlers/libpod/containers_create.go
@@ -1,7 +1,6 @@
package libpod
import (
- "context"
"encoding/json"
"fmt"
"net/http"
@@ -63,12 +62,12 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), runtime, &sg, false, nil)
+ rtSpec, spec, opts, err := generate.MakeContainer(r.Context(), runtime, &sg, false, nil)
if err != nil {
utils.InternalServerError(w, err)
return
}
- ctr, err := generate.ExecuteCreate(context.Background(), runtime, rtSpec, spec, false, opts...)
+ ctr, err := generate.ExecuteCreate(r.Context(), runtime, rtSpec, spec, false, opts...)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/libpod/generate.go b/pkg/api/handlers/libpod/generate.go
index 48c4c59e1..9b38829ad 100644
--- a/pkg/api/handlers/libpod/generate.go
+++ b/pkg/api/handlers/libpod/generate.go
@@ -17,20 +17,21 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
query := struct {
- Name bool `schema:"useName"`
- New bool `schema:"new"`
- NoHeader bool `schema:"noHeader"`
- TemplateUnitFile bool `schema:"templateUnitFile"`
- RestartPolicy *string `schema:"restartPolicy"`
- RestartSec uint `schema:"restartSec"`
- StopTimeout uint `schema:"stopTimeout"`
- StartTimeout uint `schema:"startTimeout"`
- ContainerPrefix *string `schema:"containerPrefix"`
- PodPrefix *string `schema:"podPrefix"`
- Separator *string `schema:"separator"`
- Wants []string `schema:"wants"`
- After []string `schema:"after"`
- Requires []string `schema:"requires"`
+ Name bool `schema:"useName"`
+ New bool `schema:"new"`
+ NoHeader bool `schema:"noHeader"`
+ TemplateUnitFile bool `schema:"templateUnitFile"`
+ RestartPolicy *string `schema:"restartPolicy"`
+ RestartSec uint `schema:"restartSec"`
+ StopTimeout uint `schema:"stopTimeout"`
+ StartTimeout uint `schema:"startTimeout"`
+ ContainerPrefix *string `schema:"containerPrefix"`
+ PodPrefix *string `schema:"podPrefix"`
+ Separator *string `schema:"separator"`
+ Wants []string `schema:"wants"`
+ After []string `schema:"after"`
+ Requires []string `schema:"requires"`
+ AdditionalEnvVariables []string `schema:"additionalEnvVariables"`
}{
StartTimeout: 0,
StopTimeout: util.DefaultContainerConfig().Engine.StopTimeout,
@@ -58,25 +59,26 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) {
containerEngine := abi.ContainerEngine{Libpod: runtime}
options := entities.GenerateSystemdOptions{
- Name: query.Name,
- New: query.New,
- NoHeader: query.NoHeader,
- TemplateUnitFile: query.TemplateUnitFile,
- RestartPolicy: query.RestartPolicy,
- StartTimeout: &query.StartTimeout,
- StopTimeout: &query.StopTimeout,
- ContainerPrefix: ContainerPrefix,
- PodPrefix: PodPrefix,
- Separator: Separator,
- RestartSec: &query.RestartSec,
- Wants: query.Wants,
- After: query.After,
- Requires: query.Requires,
+ Name: query.Name,
+ New: query.New,
+ NoHeader: query.NoHeader,
+ TemplateUnitFile: query.TemplateUnitFile,
+ RestartPolicy: query.RestartPolicy,
+ StartTimeout: &query.StartTimeout,
+ StopTimeout: &query.StopTimeout,
+ ContainerPrefix: ContainerPrefix,
+ PodPrefix: PodPrefix,
+ Separator: Separator,
+ RestartSec: &query.RestartSec,
+ Wants: query.Wants,
+ After: query.After,
+ Requires: query.Requires,
+ AdditionalEnvVariables: query.AdditionalEnvVariables,
}
report, err := containerEngine.GenerateSystemd(r.Context(), utils.GetName(r), options)
if err != nil {
- utils.Error(w, http.StatusInternalServerError, fmt.Errorf("error generating systemd units: %w", err))
+ utils.Error(w, http.StatusInternalServerError, fmt.Errorf("generating systemd units: %w", err))
return
}
@@ -102,7 +104,7 @@ func GenerateKube(w http.ResponseWriter, r *http.Request) {
options := entities.GenerateKubeOptions{Service: query.Service}
report, err := containerEngine.GenerateKube(r.Context(), query.Names, options)
if err != nil {
- utils.Error(w, http.StatusInternalServerError, fmt.Errorf("error generating YAML: %w", err))
+ utils.Error(w, http.StatusInternalServerError, fmt.Errorf("generating YAML: %w", err))
return
}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 67943ecf1..82c1971cd 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/buildah"
"github.com/containers/common/libimage"
+ "github.com/containers/common/pkg/ssh"
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v4/libpod"
"github.com/containers/podman/v4/libpod/define"
@@ -547,6 +548,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
Ignore bool `schema:"ignore"`
LookupManifest bool `schema:"lookupManifest"`
Images []string `schema:"images"`
+ NoPrune bool `schema:"noprune"`
}{}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
@@ -554,7 +556,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
return
}
- opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force, Ignore: query.Ignore, LookupManifest: query.LookupManifest}
+ opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force, Ignore: query.Ignore, LookupManifest: query.LookupManifest, NoPrune: query.NoPrune}
imageEngine := abi.ImageEngine{Libpod: runtime}
rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts)
strErrs := errorhandling.ErrorsToStrings(rmErrors)
@@ -617,7 +619,7 @@ func ImageScp(w http.ResponseWriter, r *http.Request) {
sourceArg := utils.GetName(r)
- rep, source, dest, _, err := domainUtils.ExecuteTransfer(sourceArg, query.Destination, []string{}, query.Quiet)
+ rep, source, dest, _, err := domainUtils.ExecuteTransfer(sourceArg, query.Destination, []string{}, query.Quiet, ssh.GolangMode)
if err != nil {
utils.Error(w, http.StatusInternalServerError, err)
return
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
index 7e24ae5ac..57b2e3a78 100644
--- a/pkg/api/handlers/libpod/images_pull.go
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -82,17 +82,32 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
pullOptions.IdentityToken = authConf.IdentityToken
}
- writer := channel.NewWriter(make(chan []byte))
- defer writer.Close()
-
- pullOptions.Writer = writer
-
pullPolicy, err := config.ParsePullPolicy(query.PullPolicy)
if err != nil {
utils.Error(w, http.StatusBadRequest, err)
return
}
+ // Let's keep thing simple when running in quiet mode and pull directly.
+ if query.Quiet {
+ images, err := runtime.LibimageRuntime().Pull(r.Context(), query.Reference, pullPolicy, pullOptions)
+ var report entities.ImagePullReport
+ if err != nil {
+ report.Error = err.Error()
+ }
+ for _, image := range images {
+ report.Images = append(report.Images, image.ID())
+ // Pull last ID from list and publish in 'id' stanza. This maintains previous API contract
+ report.ID = image.ID()
+ }
+ utils.WriteResponse(w, http.StatusOK, report)
+ return
+ }
+
+ writer := channel.NewWriter(make(chan []byte))
+ defer writer.Close()
+ pullOptions.Writer = writer
+
var pulledImages []*libimage.Image
var pullError error
runCtx, cancel := context.WithCancel(r.Context())
@@ -118,10 +133,8 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
select {
case s := <-writer.Chan():
report.Stream = string(s)
- if !query.Quiet {
- if err := enc.Encode(report); err != nil {
- logrus.Warnf("Failed to encode json: %v", err)
- }
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to encode json: %v", err)
}
flush()
case <-runCtx.Done():
diff --git a/pkg/api/handlers/libpod/images_push.go b/pkg/api/handlers/libpod/images_push.go
index e931fd2f9..4102f23de 100644
--- a/pkg/api/handlers/libpod/images_push.go
+++ b/pkg/api/handlers/libpod/images_push.go
@@ -90,8 +90,8 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
// Let's keep thing simple when running in quiet mode and push directly.
if query.Quiet {
- if err := imageEngine.Push(context.Background(), source, destination, options); err != nil {
- utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err))
+ if err := imageEngine.Push(r.Context(), source, destination, options); err != nil {
+ utils.Error(w, http.StatusBadRequest, fmt.Errorf("pushing image %q: %w", destination, err))
return
}
utils.WriteResponse(w, http.StatusOK, "")
diff --git a/pkg/api/handlers/libpod/kube.go b/pkg/api/handlers/libpod/kube.go
index 6cad58795..2a61d1723 100644
--- a/pkg/api/handlers/libpod/kube.go
+++ b/pkg/api/handlers/libpod/kube.go
@@ -103,7 +103,7 @@ func KubePlay(w http.ResponseWriter, r *http.Request) {
report, err := containerEngine.PlayKube(r.Context(), r.Body, options)
_ = r.Body.Close()
if err != nil {
- utils.Error(w, http.StatusInternalServerError, fmt.Errorf("error playing YAML file: %w", err))
+ utils.Error(w, http.StatusInternalServerError, fmt.Errorf("playing YAML file: %w", err))
return
}
utils.WriteResponse(w, http.StatusOK, report)
@@ -116,8 +116,12 @@ func KubePlayDown(w http.ResponseWriter, r *http.Request) {
report, err := containerEngine.PlayKubeDown(r.Context(), r.Body, *options)
_ = r.Body.Close()
if err != nil {
- utils.Error(w, http.StatusInternalServerError, fmt.Errorf("error tearing down YAML file: %w", err))
+ utils.Error(w, http.StatusInternalServerError, fmt.Errorf("tearing down YAML file: %w", err))
return
}
utils.WriteResponse(w, http.StatusOK, report)
}
+
+func KubeGenerate(w http.ResponseWriter, r *http.Request) {
+ GenerateKube(w, r)
+}
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index 2d6223e4e..d5af72a61 100644
--- a/pkg/api/handlers/libpod/manifests.go
+++ b/pkg/api/handlers/libpod/manifests.go
@@ -19,12 +19,14 @@ import (
"github.com/containers/podman/v4/pkg/api/handlers/utils"
api "github.com/containers/podman/v4/pkg/api/types"
"github.com/containers/podman/v4/pkg/auth"
+ "github.com/containers/podman/v4/pkg/channel"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/domain/infra/abi"
"github.com/containers/podman/v4/pkg/errorhandling"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/opencontainers/go-digest"
+ "github.com/sirupsen/logrus"
)
func ManifestCreate(w http.ResponseWriter, r *http.Request) {
@@ -34,6 +36,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
Name string `schema:"name"`
Images []string `schema:"images"`
All bool `schema:"all"`
+ Amend bool `schema:"amend"`
}{
// Add defaults here once needed.
}
@@ -68,7 +71,7 @@ func ManifestCreate(w http.ResponseWriter, r *http.Request) {
imageEngine := abi.ImageEngine{Libpod: runtime}
- createOptions := entities.ManifestCreateOptions{All: query.All}
+ createOptions := entities.ManifestCreateOptions{All: query.All, Amend: query.Amend}
manID, err := imageEngine.ManifestCreate(r.Context(), query.Name, query.Images, createOptions)
if err != nil {
utils.InternalServerError(w, err)
@@ -290,9 +293,9 @@ func ManifestPushV3(w http.ResponseWriter, r *http.Request) {
options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
}
imageEngine := abi.ImageEngine{Libpod: runtime}
- digest, err := imageEngine.ManifestPush(context.Background(), source, query.Destination, options)
+ digest, err := imageEngine.ManifestPush(r.Context(), source, query.Destination, options)
if err != nil {
- utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", query.Destination, err))
+ utils.Error(w, http.StatusBadRequest, fmt.Errorf("pushing image %q: %w", query.Destination, err))
return
}
utils.WriteResponse(w, http.StatusOK, entities.IDResponse{ID: digest})
@@ -311,9 +314,13 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) {
Format string `schema:"format"`
RemoveSignatures bool `schema:"removeSignatures"`
TLSVerify bool `schema:"tlsVerify"`
+ Quiet bool `schema:"quiet"`
}{
// Add defaults here once needed.
TLSVerify: true,
+ // #15210: older versions did not sent *any* data, so we need
+ // to be quiet by default to remain backwards compatible
+ Quiet: true,
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusBadRequest,
@@ -344,6 +351,7 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) {
CompressionFormat: query.CompressionFormat,
Format: query.Format,
Password: password,
+ Quiet: true,
RemoveSignatures: query.RemoveSignatures,
Username: username,
}
@@ -356,12 +364,67 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) {
imageEngine := abi.ImageEngine{Libpod: runtime}
source := utils.GetName(r)
- digest, err := imageEngine.ManifestPush(context.Background(), source, destination, options)
- if err != nil {
- utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err))
+
+ // Let's keep thing simple when running in quiet mode and push directly.
+ if query.Quiet {
+ digest, err := imageEngine.ManifestPush(r.Context(), source, destination, options)
+ if err != nil {
+ utils.Error(w, http.StatusBadRequest, fmt.Errorf("pushing image %q: %w", destination, err))
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, entities.ManifestPushReport{ID: digest})
return
}
- utils.WriteResponse(w, http.StatusOK, entities.IDResponse{ID: digest})
+
+ writer := channel.NewWriter(make(chan []byte))
+ defer writer.Close()
+ options.Writer = writer
+
+ pushCtx, pushCancel := context.WithCancel(r.Context())
+ var digest string
+ var pushError error
+ go func() {
+ defer pushCancel()
+ digest, pushError = imageEngine.ManifestPush(pushCtx, source, destination, options)
+ }()
+
+ flush := func() {
+ if flusher, ok := w.(http.Flusher); ok {
+ flusher.Flush()
+ }
+ }
+
+ w.WriteHeader(http.StatusOK)
+ w.Header().Set("Content-Type", "application/json")
+ flush()
+
+ enc := json.NewEncoder(w)
+ enc.SetEscapeHTML(true)
+ for {
+ var report entities.ManifestPushReport
+ select {
+ case s := <-writer.Chan():
+ report.Stream = string(s)
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to encode json: %v", err)
+ }
+ flush()
+ case <-pushCtx.Done():
+ if pushError != nil {
+ report.Error = pushError.Error()
+ } else {
+ report.ID = digest
+ }
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to encode json: %v", err)
+ }
+ flush()
+ return
+ case <-r.Context().Done():
+ // Client has closed connection
+ return
+ }
+ }
}
// ManifestModify efficiently updates the named manifest list
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 8b1d456ec..c39b9ee2f 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -51,7 +51,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
}
err = specgenutil.FillOutSpecGen(psg.InfraContainerSpec, &infraOptions, []string{}) // necessary for default values in many cases (userns, idmappings)
if err != nil {
- utils.Error(w, http.StatusInternalServerError, fmt.Errorf("error filling out specgen: %w", err))
+ utils.Error(w, http.StatusInternalServerError, fmt.Errorf("filling out specgen: %w", err))
return
}
out, err := json.Marshal(psg) // marshal our spec so the matching options can be unmarshaled into infra
@@ -178,7 +178,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
report := entities.PodStopReport{Id: pod.ID()}
for id, err := range responses {
- report.Errs = append(report.Errs, fmt.Errorf("error stopping container %s: %w", id, err))
+ report.Errs = append(report.Errs, fmt.Errorf("stopping container %s: %w", id, err))
}
code := http.StatusOK
@@ -214,7 +214,7 @@ func PodStart(w http.ResponseWriter, r *http.Request) {
report := entities.PodStartReport{Id: pod.ID()}
for id, err := range responses {
- report.Errs = append(report.Errs, fmt.Errorf("%v: %w", "error starting container "+id, err))
+ report.Errs = append(report.Errs, fmt.Errorf("%v: %w", "starting container "+id, err))
}
code := http.StatusOK
@@ -270,7 +270,7 @@ func PodRestart(w http.ResponseWriter, r *http.Request) {
report := entities.PodRestartReport{Id: pod.ID()}
for id, err := range responses {
- report.Errs = append(report.Errs, fmt.Errorf("error restarting container %s: %w", id, err))
+ report.Errs = append(report.Errs, fmt.Errorf("restarting container %s: %w", id, err))
}
code := http.StatusOK
@@ -321,7 +321,7 @@ func PodPause(w http.ResponseWriter, r *http.Request) {
report := entities.PodPauseReport{Id: pod.ID()}
for id, v := range responses {
- report.Errs = append(report.Errs, fmt.Errorf("error pausing container %s: %w", id, v))
+ report.Errs = append(report.Errs, fmt.Errorf("pausing container %s: %w", id, v))
}
code := http.StatusOK
@@ -347,7 +347,7 @@ func PodUnpause(w http.ResponseWriter, r *http.Request) {
report := entities.PodUnpauseReport{Id: pod.ID()}
for id, v := range responses {
- report.Errs = append(report.Errs, fmt.Errorf("error unpausing container %s: %w", id, v))
+ report.Errs = append(report.Errs, fmt.Errorf("unpausing container %s: %w", id, v))
}
code := http.StatusOK