diff options
Diffstat (limited to 'pkg/api/handlers/libpod')
-rw-r--r-- | pkg/api/handlers/libpod/containers.go | 24 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/images.go | 90 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/networks.go | 18 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/pods.go | 102 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/volumes.go | 14 |
5 files changed, 141 insertions, 107 deletions
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index deddcaf93..5d85d4009 100644 --- a/pkg/api/handlers/libpod/containers.go +++ b/pkg/api/handlers/libpod/containers.go @@ -1,6 +1,7 @@ package libpod import ( + "errors" "fmt" "io/ioutil" "net/http" @@ -16,7 +17,6 @@ import ( "github.com/containers/podman/v4/pkg/domain/infra/abi" "github.com/containers/podman/v4/pkg/util" "github.com/gorilla/schema" - "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -35,7 +35,7 @@ func ContainerExists(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -45,7 +45,7 @@ func ContainerExists(w http.ResponseWriter, r *http.Request) { report, err := containerEngine.ContainerExists(r.Context(), name, options) if err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { + if errors.Is(err, define.ErrNoSuchCtr) { utils.ContainerNotFound(w, name, err) return } @@ -75,12 +75,12 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { filterMap, err := util.PrepareFilters(r) if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "failed to decode filter parameters for %s", r.URL.String())) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to decode filter parameters for %s: %w", r.URL.String(), err)) return } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -127,7 +127,7 @@ func GetContainer(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) @@ -221,7 +221,7 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -307,7 +307,7 @@ func Restore(w http.ResponseWriter, r *http.Request) { // override any golang type defaults } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -344,11 +344,11 @@ func Restore(w http.ResponseWriter, r *http.Request) { ir := abi.ImageEngine{Libpod: runtime} report, err := ir.Exists(r.Context(), name) if err != nil { - utils.Error(w, http.StatusNotFound, errors.Wrapf(err, "failed to find container or checkpoint image %s", name)) + utils.Error(w, http.StatusNotFound, fmt.Errorf("failed to find container or checkpoint image %s: %w", name, err)) return } if !report.Value { - utils.Error(w, http.StatusNotFound, errors.Errorf("failed to find container or checkpoint image %s", name)) + utils.Error(w, http.StatusNotFound, fmt.Errorf("failed to find container or checkpoint image %s", name)) return } } @@ -380,7 +380,7 @@ func InitContainer(w http.ResponseWriter, r *http.Request) { return } err = ctr.Init(r.Context(), ctr.PodID() != "") - if errors.Cause(err) == define.ErrCtrStateInvalid { + if errors.Is(err, define.ErrCtrStateInvalid) { utils.Error(w, http.StatusNotModified, err) return } @@ -400,7 +400,7 @@ func ShouldRestart(w http.ResponseWriter, r *http.Request) { name := utils.GetName(r) report, err := containerEngine.ShouldRestart(r.Context(), name) if err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { + if errors.Is(err, define.ErrNoSuchCtr) { utils.ContainerNotFound(w, name, err) return } diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index b71217efa..ed1c65f8e 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -2,6 +2,7 @@ package libpod import ( "context" + "errors" "fmt" "io" "io/ioutil" @@ -29,7 +30,6 @@ import ( utils2 "github.com/containers/podman/v4/utils" "github.com/containers/storage" "github.com/gorilla/schema" - "github.com/pkg/errors" ) // Commit @@ -50,11 +50,11 @@ func ImageExists(w http.ResponseWriter, r *http.Request) { ir := abi.ImageEngine{Libpod: runtime} report, err := ir.Exists(r.Context(), name) if err != nil { - utils.Error(w, http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name)) + utils.Error(w, http.StatusNotFound, fmt.Errorf("failed to find image %s: %w", name, err)) return } if !report.Value { - utils.Error(w, http.StatusNotFound, errors.Errorf("failed to find image %s", name)) + utils.Error(w, http.StatusNotFound, fmt.Errorf("failed to find image %s", name)) return } utils.WriteResponse(w, http.StatusNoContent, "") @@ -70,18 +70,18 @@ func ImageTree(w http.ResponseWriter, r *http.Request) { WhatRequires: false, } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } ir := abi.ImageEngine{Libpod: runtime} options := entities.ImageTreeOptions{WhatRequires: query.WhatRequires} report, err := ir.Tree(r.Context(), name, options) if err != nil { - if errors.Cause(err) == storage.ErrImageUnknown { - utils.Error(w, http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name)) + if errors.Is(err, storage.ErrImageUnknown) { + utils.Error(w, http.StatusNotFound, fmt.Errorf("failed to find image %s: %w", name, err)) return } - utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "failed to generate image tree for %s", name)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to generate image tree for %s: %w", name, err)) return } utils.WriteResponse(w, http.StatusOK, report) @@ -91,13 +91,13 @@ func GetImage(w http.ResponseWriter, r *http.Request) { name := utils.GetName(r) newImage, err := utils.GetImage(r, name) if err != nil { - utils.Error(w, http.StatusNotFound, errors.Wrapf(err, "failed to find image %s", name)) + utils.Error(w, http.StatusNotFound, fmt.Errorf("failed to find image %s: %w", name, err)) return } options := &libimage.InspectOptions{WithParent: true, WithSize: true} inspect, err := newImage.Inspect(r.Context(), options) if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "failed in inspect image %s", inspect.ID)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed in inspect image %s: %w", inspect.ID, err)) return } utils.WriteResponse(w, http.StatusOK, inspect) @@ -117,15 +117,13 @@ func PruneImages(w http.ResponseWriter, r *http.Request) { filterMap, err := util.PrepareFilters(r) if err != nil { utils.Error(w, http.StatusInternalServerError, - errors. - Wrapf(err, "failed to decode filter parameters for %s", r.URL.String())) + fmt.Errorf("failed to decode filter parameters for %s: %w", r.URL.String(), err)) return } if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusInternalServerError, - errors. - Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -174,7 +172,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) { if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusBadRequest, - errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } name := utils.GetName(r) @@ -188,23 +186,23 @@ func ExportImage(w http.ResponseWriter, r *http.Request) { case define.OCIArchive, define.V2s2Archive: tmpfile, err := ioutil.TempFile("", "api.tar") if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to create tempfile: %w", err)) return } output = tmpfile.Name() if err := tmpfile.Close(); err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to close tempfile: %w", err)) return } case define.OCIManifestDir, define.V2s2ManifestDir: tmpdir, err := ioutil.TempDir("", "save") if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempdir")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to create tempdir: %w", err)) return } output = tmpdir default: - utils.Error(w, http.StatusInternalServerError, errors.Errorf("unknown format %q", query.Format)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unknown format %q", query.Format)) return } @@ -233,7 +231,7 @@ func ExportImage(w http.ResponseWriter, r *http.Request) { } rdr, err := os.Open(output) if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "failed to read the exported tarfile")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to read the exported tarfile: %w", err)) return } defer rdr.Close() @@ -254,20 +252,20 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } // References are mandatory! if len(query.References) == 0 { - utils.Error(w, http.StatusBadRequest, errors.New("No references")) + utils.Error(w, http.StatusBadRequest, errors.New("no references")) return } // Format is mandatory! Currently, we only support multi-image docker // archives. if len(query.References) > 1 && query.Format != define.V2s2Archive { - utils.Error(w, http.StatusInternalServerError, errors.Errorf("multi-image archives must use format of %s", define.V2s2Archive)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("multi-image archives must use format of %s", define.V2s2Archive)) return } @@ -285,23 +283,23 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { case define.V2s2Archive, define.OCIArchive: tmpfile, err := ioutil.TempFile("", "api.tar") if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to create tempfile: %w", err)) return } output = tmpfile.Name() if err := tmpfile.Close(); err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to close tempfile")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to close tempfile: %w", err)) return } case define.OCIManifestDir, define.V2s2ManifestDir: tmpdir, err := ioutil.TempDir("", "save") if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tmpdir")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to create tmpdir: %w", err)) return } output = tmpdir default: - utils.Error(w, http.StatusInternalServerError, errors.Errorf("unsupported format %q", query.Format)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unsupported format %q", query.Format)) return } defer os.RemoveAll(output) @@ -323,7 +321,7 @@ func ExportImages(w http.ResponseWriter, r *http.Request) { rdr, err := os.Open(output) if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "failed to read the exported tarfile")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to read the exported tarfile: %w", err)) return } defer rdr.Close() @@ -335,7 +333,7 @@ func ImagesLoad(w http.ResponseWriter, r *http.Request) { tmpfile, err := ioutil.TempFile("", "libpod-images-load.tar") if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to create tempfile: %w", err)) return } defer os.Remove(tmpfile.Name()) @@ -344,7 +342,7 @@ func ImagesLoad(w http.ResponseWriter, r *http.Request) { tmpfile.Close() if err != nil && err != io.EOF { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to write archive to temporary file: %w", err)) return } @@ -353,7 +351,7 @@ func ImagesLoad(w http.ResponseWriter, r *http.Request) { loadOptions := entities.ImageLoadOptions{Input: tmpfile.Name()} loadReport, err := imageEngine.Load(r.Context(), loadOptions) if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to load image")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to load image: %w", err)) return } utils.WriteResponse(w, http.StatusOK, loadReport) @@ -375,7 +373,7 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -384,14 +382,14 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) { if len(query.URL) == 0 { tmpfile, err := ioutil.TempFile("", "libpod-images-import.tar") if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to create tempfile: %w", err)) return } defer os.Remove(tmpfile.Name()) defer tmpfile.Close() if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to write archive to temporary file: %w", err)) return } @@ -411,7 +409,7 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) { } report, err := imageEngine.Import(r.Context(), importOptions) if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "unable to import tarball")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("unable to import tarball: %w", err)) return } @@ -433,7 +431,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) { // This is where you can override the golang default value for one of fields } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -479,7 +477,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) { imageEngine := abi.ImageEngine{Libpod: runtime} if err := imageEngine.Push(context.Background(), source, destination, options); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "error pushing image %q", destination)) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("error pushing image %q: %w", destination, err)) return } @@ -509,12 +507,12 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } rtc, err := runtime.GetConfig() if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "failed to get runtime config")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to get runtime config: %w", err)) return } sc := runtime.SystemContext() @@ -532,7 +530,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) { case "docker": mimeType = manifest.DockerV2Schema2MediaType default: - utils.InternalServerError(w, errors.Errorf("unrecognized image format %q", query.Format)) + utils.InternalServerError(w, fmt.Errorf("unrecognized image format %q", query.Format)) return } options.CommitOptions = buildah.CommitOptions{ @@ -561,7 +559,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) { } commitImage, err := ctr.Commit(r.Context(), destImage, options) if err != nil && !strings.Contains(err.Error(), "is not running") { - utils.Error(w, http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("CommitFailure: %w", err)) return } utils.WriteResponse(w, http.StatusOK, entities.IDResponse{ID: commitImage.ID()}) @@ -600,8 +598,8 @@ func UntagImage(w http.ResponseWriter, r *http.Request) { name := utils.GetName(r) if err := imageEngine.Untag(r.Context(), name, tags, opts); err != nil { - if errors.Cause(err) == storage.ErrImageUnknown { - utils.ImageNotFound(w, name, errors.Wrapf(err, "failed to find image %s", name)) + if errors.Is(err, storage.ErrImageUnknown) { + utils.ImageNotFound(w, name, fmt.Errorf("failed to find image %s: %w", name, err)) } else { utils.Error(w, http.StatusInternalServerError, err) } @@ -623,7 +621,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) { }{} if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -647,7 +645,7 @@ func ImagesRemove(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -684,7 +682,7 @@ func ImageScp(w http.ResponseWriter, r *http.Request) { // This is where you can override the golang default value for one of fields } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -697,7 +695,7 @@ func ImageScp(w http.ResponseWriter, r *http.Request) { } if source != nil || dest != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(define.ErrInvalidArg, "cannot use the user transfer function on the remote client")) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("cannot use the user transfer function on the remote client: %w", define.ErrInvalidArg)) return } diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go index 16f499d4c..7169a6d44 100644 --- a/pkg/api/handlers/libpod/networks.go +++ b/pkg/api/handlers/libpod/networks.go @@ -2,8 +2,11 @@ package libpod import ( "encoding/json" + "fmt" "net/http" + "errors" + "github.com/containers/common/libnetwork/types" "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" @@ -13,7 +16,6 @@ import ( "github.com/containers/podman/v4/pkg/domain/infra/abi" "github.com/containers/podman/v4/pkg/util" "github.com/gorilla/schema" - "github.com/pkg/errors" ) func CreateNetwork(w http.ResponseWriter, r *http.Request) { @@ -25,7 +27,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) network := types.Network{} if err := json.NewDecoder(r.Body).Decode(&network); err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "failed to decode request JSON payload")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to decode request JSON payload: %w", err)) return } @@ -52,7 +54,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) { filterMap, err := util.PrepareFilters(r) if err != nil { utils.Error(w, http.StatusInternalServerError, - errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -83,7 +85,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusInternalServerError, - errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } name := utils.GetName(r) @@ -99,7 +101,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) { } if reports[0].Err != nil { // If the network cannot be found, we return a 404. - if errors.Cause(reports[0].Err) == define.ErrNoSuchNetwork { + if errors.Is(reports[0].Err, define.ErrNoSuchNetwork) { utils.Error(w, http.StatusNotFound, reports[0].Err) return } @@ -142,18 +144,18 @@ func Connect(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime) var netConnect entities.NetworkConnectOptions if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "failed to decode request JSON payload")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("failed to decode request JSON payload: %w", err)) return } name := utils.GetName(r) err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netConnect.PerNetworkOptions) if err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { + if errors.Is(err, define.ErrNoSuchCtr) { utils.ContainerNotFound(w, netConnect.Container, err) return } - if errors.Cause(err) == define.ErrNoSuchNetwork { + if errors.Is(err, define.ErrNoSuchNetwork) { utils.Error(w, http.StatusNotFound, err) return } diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index 5b92358fa..8b1d456ec 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -2,6 +2,7 @@ package libpod import ( "encoding/json" + "errors" "fmt" "net/http" "strings" @@ -19,7 +20,6 @@ import ( "github.com/containers/podman/v4/pkg/specgenutil" "github.com/containers/podman/v4/pkg/util" "github.com/gorilla/schema" - "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -33,11 +33,11 @@ func PodCreate(w http.ResponseWriter, r *http.Request) { ) psg := specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}} if err := json.NewDecoder(r.Body).Decode(&psg); err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, failedToDecodeSpecgen)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("%v: %w", failedToDecodeSpecgen, err)) return } if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, failedToDecodeSpecgen)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("%v: %w", failedToDecodeSpecgen, err)) return } if !psg.NoInfra { @@ -51,17 +51,17 @@ 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, errors.Wrap(err, "error filling out specgen")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("error filling out specgen: %w", err)) return } out, err := json.Marshal(psg) // marshal our spec so the matching options can be unmarshaled into infra if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, failedToDecodeSpecgen)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("%v: %w", failedToDecodeSpecgen, err)) return } err = json.Unmarshal(out, psg.InfraContainerSpec) // unmarhal matching options if err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, failedToDecodeSpecgen)) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("%v: %w", failedToDecodeSpecgen, err)) return } // a few extra that do not have the same json tags @@ -75,10 +75,10 @@ func PodCreate(w http.ResponseWriter, r *http.Request) { pod, err := generate.MakePod(&podSpecComplete, runtime) if err != nil { httpCode := http.StatusInternalServerError - if errors.Cause(err) == define.ErrPodExists { + if errors.Is(err, define.ErrPodExists) { httpCode = http.StatusConflict } - utils.Error(w, httpCode, errors.Wrap(err, "failed to make pod")) + utils.Error(w, httpCode, fmt.Errorf("failed to make pod: %w", err)) return } utils.WriteResponse(w, http.StatusCreated, entities.IDResponse{ID: pod.ID()}) @@ -89,7 +89,7 @@ func Pods(w http.ResponseWriter, r *http.Request) { filterMap, err := util.PrepareFilters(r) if err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -139,7 +139,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } name := utils.GetName(r) @@ -164,7 +164,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) { } else { responses, stopError = pod.Stop(r.Context(), false) } - if stopError != nil && errors.Cause(stopError) != define.ErrPodPartialFail { + if stopError != nil && !errors.Is(stopError, define.ErrPodPartialFail) { utils.Error(w, http.StatusInternalServerError, err) return } @@ -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, errors.Wrapf(err, "error stopping container %s", id)) + report.Errs = append(report.Errs, fmt.Errorf("error stopping container %s: %w", id, err)) } code := http.StatusOK @@ -207,14 +207,14 @@ func PodStart(w http.ResponseWriter, r *http.Request) { } responses, err := pod.Start(r.Context()) - if err != nil && errors.Cause(err) != define.ErrPodPartialFail { + if err != nil && !errors.Is(err, define.ErrPodPartialFail) { utils.Error(w, http.StatusConflict, err) return } report := entities.PodStartReport{Id: pod.ID()} for id, err := range responses { - report.Errs = append(report.Errs, errors.Wrapf(err, "error starting container "+id)) + report.Errs = append(report.Errs, fmt.Errorf("%v: %w", "error starting container "+id, err)) } code := http.StatusOK @@ -237,7 +237,7 @@ func PodDelete(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } name := utils.GetName(r) @@ -263,14 +263,14 @@ func PodRestart(w http.ResponseWriter, r *http.Request) { return } responses, err := pod.Restart(r.Context()) - if err != nil && errors.Cause(err) != define.ErrPodPartialFail { + if err != nil && !errors.Is(err, define.ErrPodPartialFail) { utils.Error(w, http.StatusInternalServerError, err) return } report := entities.PodRestartReport{Id: pod.ID()} for id, err := range responses { - report.Errs = append(report.Errs, errors.Wrapf(err, "error restarting container %s", id)) + report.Errs = append(report.Errs, fmt.Errorf("error restarting container %s: %w", id, err)) } code := http.StatusOK @@ -314,14 +314,14 @@ func PodPause(w http.ResponseWriter, r *http.Request) { return } responses, err := pod.Pause(r.Context()) - if err != nil && errors.Cause(err) != define.ErrPodPartialFail { + if err != nil && !errors.Is(err, define.ErrPodPartialFail) { utils.Error(w, http.StatusInternalServerError, err) return } report := entities.PodPauseReport{Id: pod.ID()} for id, v := range responses { - report.Errs = append(report.Errs, errors.Wrapf(v, "error pausing container %s", id)) + report.Errs = append(report.Errs, fmt.Errorf("error pausing container %s: %w", id, v)) } code := http.StatusOK @@ -340,14 +340,14 @@ func PodUnpause(w http.ResponseWriter, r *http.Request) { return } responses, err := pod.Unpause(r.Context()) - if err != nil && errors.Cause(err) != define.ErrPodPartialFail { + if err != nil && !errors.Is(err, define.ErrPodPartialFail) { utils.Error(w, http.StatusInternalServerError, err) return } report := entities.PodUnpauseReport{Id: pod.ID()} for id, v := range responses { - report.Errs = append(report.Errs, errors.Wrapf(v, "error unpausing container %s", id)) + report.Errs = append(report.Errs, fmt.Errorf("error unpausing container %s: %w", id, v)) } code := http.StatusOK @@ -374,7 +374,7 @@ func PodTop(w http.ResponseWriter, r *http.Request) { PsArgs: psArgs, } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -456,7 +456,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) { // override any golang type defaults } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } if _, found := r.URL.Query()["signal"]; found { @@ -465,7 +465,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) { sig, err := util.ParseSignal(signal) if err != nil { - utils.InternalServerError(w, errors.Wrapf(err, "unable to parse signal value")) + utils.InternalServerError(w, fmt.Errorf("unable to parse signal value: %w", err)) return } name := utils.GetName(r) @@ -488,12 +488,12 @@ func PodKill(w http.ResponseWriter, r *http.Request) { } } if !hasRunning { - utils.Error(w, http.StatusConflict, errors.Errorf("cannot kill a pod with no running containers: %s", pod.ID())) + utils.Error(w, http.StatusConflict, fmt.Errorf("cannot kill a pod with no running containers: %s", pod.ID())) return } responses, err := pod.Kill(r.Context(), uint(sig)) - if err != nil && errors.Cause(err) != define.ErrPodPartialFail { + if err != nil && !errors.Is(err, define.ErrPodPartialFail) { utils.Error(w, http.StatusInternalServerError, err) return } @@ -530,11 +530,15 @@ func PodStats(w http.ResponseWriter, r *http.Request) { query := struct { NamesOrIDs []string `schema:"namesOrIDs"` All bool `schema:"all"` + Stream bool `schema:"stream"` + Delay int `schema:"delay"` }{ // default would go here + Delay: 5, + Stream: false, } if err := decoder.Decode(&query, r.URL.Query()); err != nil { - utils.Error(w, http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -544,21 +548,49 @@ func PodStats(w http.ResponseWriter, r *http.Request) { utils.InternalServerError(w, err) } + var flush = func() {} + if flusher, ok := w.(http.Flusher); ok { + flush = flusher.Flush + } // Collect the stats and send them over the wire. containerEngine := abi.ContainerEngine{Libpod: runtime} reports, err := containerEngine.PodStats(r.Context(), query.NamesOrIDs, options) // Error checks as documented in swagger. - switch errors.Cause(err) { - case define.ErrNoSuchPod: - utils.Error(w, http.StatusNotFound, err) - return - case nil: - // Nothing to do. - default: + if err != nil { + if errors.Is(err, define.ErrNoSuchPod) { + utils.Error(w, http.StatusNotFound, err) + return + } utils.InternalServerError(w, err) return } - utils.WriteResponse(w, http.StatusOK, reports) + w.Header().Set("Content-Type", "application/json") + coder := json.NewEncoder(w) + coder.SetEscapeHTML(true) + + if err := coder.Encode(reports); err != nil { + logrus.Infof("Error from %s %q : %v", r.Method, r.URL, err) + } + flush() + if query.Stream { + for { + select { + case <-r.Context().Done(): + return + default: + time.Sleep(time.Duration(query.Delay) * time.Second) + reports, err = containerEngine.PodStats(r.Context(), query.NamesOrIDs, options) + if err != nil { + return + } + if err := coder.Encode(reports); err != nil { + logrus.Infof("Error from %s %q : %v", r.Method, r.URL, err) + return + } + flush() + } + } + } } diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go index e792dea35..5eac76f5b 100644 --- a/pkg/api/handlers/libpod/volumes.go +++ b/pkg/api/handlers/libpod/volumes.go @@ -2,9 +2,12 @@ package libpod import ( "encoding/json" + "fmt" "net/http" "net/url" + "errors" + "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/api/handlers/utils" @@ -16,7 +19,6 @@ import ( "github.com/containers/podman/v4/pkg/domain/infra/abi/parse" "github.com/containers/podman/v4/pkg/util" "github.com/gorilla/schema" - "github.com/pkg/errors" ) func CreateVolume(w http.ResponseWriter, r *http.Request) { @@ -30,14 +32,14 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) { } if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusInternalServerError, - errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } input := entities.VolumeCreateOptions{} // decode params from body if err := json.NewDecoder(r.Body).Decode(&input); err != nil { - utils.Error(w, http.StatusInternalServerError, errors.Wrap(err, "Decode()")) + utils.Error(w, http.StatusInternalServerError, fmt.Errorf("Decode(): %w", err)) return } @@ -108,7 +110,7 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) { filterMap, err := util.PrepareFilters(r) if err != nil { utils.Error(w, http.StatusInternalServerError, - errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } @@ -181,7 +183,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) { if err := decoder.Decode(&query, r.URL.Query()); err != nil { utils.Error(w, http.StatusInternalServerError, - errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err)) return } name := utils.GetName(r) @@ -191,7 +193,7 @@ func RemoveVolume(w http.ResponseWriter, r *http.Request) { return } if err := runtime.RemoveVolume(r.Context(), vol, query.Force, query.Timeout); err != nil { - if errors.Cause(err) == define.ErrVolumeBeingUsed { + if errors.Is(err, define.ErrVolumeBeingUsed) { utils.Error(w, http.StatusConflict, err) return } |