summaryrefslogtreecommitdiff
path: root/pkg/api
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api')
-rw-r--r--pkg/api/handlers/containers.go8
-rw-r--r--pkg/api/handlers/events.go44
-rw-r--r--pkg/api/handlers/generic/containers_stats.go3
-rw-r--r--pkg/api/handlers/libpod/images.go209
-rw-r--r--pkg/api/handlers/libpod/pods.go14
-rw-r--r--pkg/api/handlers/types.go27
-rw-r--r--pkg/api/handlers/utils/handler.go8
-rw-r--r--pkg/api/server/register_events.go2
-rw-r--r--pkg/api/server/register_images.go74
-rw-r--r--pkg/api/server/register_pods.go2
-rw-r--r--pkg/api/server/server.go1
11 files changed, 317 insertions, 75 deletions
diff --git a/pkg/api/handlers/containers.go b/pkg/api/handlers/containers.go
index f180fbc2b..d7d040ce2 100644
--- a/pkg/api/handlers/containers.go
+++ b/pkg/api/handlers/containers.go
@@ -41,10 +41,9 @@ func StopContainer(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, errors.Wrapf(err, "unable to get state for Container %s", name))
return
}
- // If the Container is stopped already, send a 302
+ // If the Container is stopped already, send a 304
if state == define.ContainerStateStopped || state == define.ContainerStateExited {
- utils.Error(w, http.StatusText(http.StatusNotModified), http.StatusNotModified,
- errors.Errorf("Container %s is already stopped ", name))
+ utils.WriteResponse(w, http.StatusNotModified, "")
return
}
@@ -134,8 +133,7 @@ func StartContainer(w http.ResponseWriter, r *http.Request) {
return
}
if state == define.ContainerStateRunning {
- msg := fmt.Sprintf("Container %s is already running", name)
- utils.Error(w, msg, http.StatusNotModified, errors.New(msg))
+ utils.WriteResponse(w, http.StatusNotModified, "")
return
}
if err := con.Start(r.Context(), false); err != nil {
diff --git a/pkg/api/handlers/events.go b/pkg/api/handlers/events.go
index 44bf35254..22dad9923 100644
--- a/pkg/api/handlers/events.go
+++ b/pkg/api/handlers/events.go
@@ -1,19 +1,24 @@
package handlers
import (
+ "encoding/json"
"fmt"
"net/http"
- "strings"
- "time"
+ "github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
func GetEvents(w http.ResponseWriter, r *http.Request) {
+ var (
+ fromStart bool
+ eventsError error
+ )
query := struct {
- Since time.Time `schema:"since"`
- Until time.Time `schema:"until"`
+ Since string `schema:"since"`
+ Until string `schema:"until"`
Filters map[string][]string `schema:"filters"`
}{}
if err := decodeQuery(r, &query); err != nil {
@@ -27,15 +32,30 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
}
}
- libpodEvents, err := getRuntime(r).GetEvents(libpodFilters)
- if err != nil {
- utils.BadRequest(w, "filters", strings.Join(r.URL.Query()["filters"], ", "), err)
+ if len(query.Since) > 0 || len(query.Until) > 0 {
+ fromStart = true
+ }
+ eventChannel := make(chan *events.Event)
+ go func() {
+ readOpts := events.ReadOptions{FromStart: fromStart, Stream: true, Filters: libpodFilters, EventChannel: eventChannel, Since: query.Since, Until: query.Until}
+ eventsError = getRuntime(r).Events(readOpts)
+ }()
+ if eventsError != nil {
+ utils.InternalServerError(w, eventsError)
return
}
-
- var apiEvents = make([]*Event, len(libpodEvents))
- for _, v := range libpodEvents {
- apiEvents = append(apiEvents, EventToApiEvent(v))
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ for event := range eventChannel {
+ e := EventToApiEvent(event)
+ //utils.WriteJSON(w, http.StatusOK, e)
+ coder := json.NewEncoder(w)
+ coder.SetEscapeHTML(true)
+ if err := coder.Encode(e); err != nil {
+ logrus.Errorf("unable to write json: %q", err)
+ }
+ if flusher, ok := w.(http.Flusher); ok {
+ flusher.Flush()
+ }
}
- utils.WriteJSON(w, http.StatusOK, apiEvents)
}
diff --git a/pkg/api/handlers/generic/containers_stats.go b/pkg/api/handlers/generic/containers_stats.go
index f8804b5c0..cbc1be2f0 100644
--- a/pkg/api/handlers/generic/containers_stats.go
+++ b/pkg/api/handlers/generic/containers_stats.go
@@ -19,9 +19,6 @@ import (
const DefaultStatsPeriod = 5 * time.Second
func StatsContainer(w http.ResponseWriter, r *http.Request) {
- // 200 no error
- // 404 no such
- // 500 internal
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 6c926c45b..bcbe4977e 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -1,15 +1,23 @@
package libpod
import (
+ "context"
"fmt"
+ "io"
"io/ioutil"
"net/http"
"os"
"strconv"
+ "github.com/containers/image/v5/docker"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/image/v5/types"
"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/containers/libpod/pkg/util"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -176,16 +184,205 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
}
func ImagesLoad(w http.ResponseWriter, r *http.Request) {
- //TODO ...
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.New("/libpod/images/load is not yet implemented"))
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Reference string `schema:"reference"`
+ }{
+ // 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
+ }
+
+ tmpfile, err := ioutil.TempFile("", "libpod-images-load.tar")
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
+ return
+ }
+ defer os.Remove(tmpfile.Name())
+ defer tmpfile.Close()
+
+ if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
+ return
+ }
+
+ tmpfile.Close()
+ loadedImage, err := runtime.LoadImage(context.Background(), query.Reference, tmpfile.Name(), os.Stderr, "")
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to load image"))
+ return
+ }
+
+ utils.WriteResponse(w, http.StatusOK, []handlers.LibpodImagesLoadReport{{ID: loadedImage}})
}
func ImagesImport(w http.ResponseWriter, r *http.Request) {
- //TODO ...
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.New("/libpod/images/import is not yet implemented"))
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Changes []string `schema:"changes"`
+ Message string `schema:"message"`
+ Reference string `schema:"reference"`
+ URL string `schema:"URL"`
+ }{
+ // 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
+ }
+
+ // Check if we need to load the image from a URL or from the request's body.
+ source := query.URL
+ if len(query.URL) == 0 {
+ tmpfile, err := ioutil.TempFile("", "libpod-images-import.tar")
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
+ return
+ }
+ defer os.Remove(tmpfile.Name())
+ defer tmpfile.Close()
+
+ if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
+ return
+ }
+
+ tmpfile.Close()
+ source = tmpfile.Name()
+ }
+
+ importedImage, err := runtime.Import(context.Background(), source, query.Reference, query.Changes, query.Message, true)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to import image"))
+ return
+ }
+
+ utils.WriteResponse(w, http.StatusOK, handlers.LibpodImagesImportReport{ID: importedImage})
}
func ImagesPull(w http.ResponseWriter, r *http.Request) {
- //TODO ...
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.New("/libpod/images/pull is not yet implemented"))
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Reference string `schema:"reference"`
+ Credentials string `schema:"credentials"`
+ OverrideOS string `schema:"overrideOS"`
+ OverrideArch string `schema:"overrideArch"`
+ TLSVerify bool `schema:"tlsVerify"`
+ AllTags bool `schema:"allTags"`
+ }{
+ TLSVerify: true,
+ }
+
+ 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
+ }
+
+ if len(query.Reference) == 0 {
+ utils.InternalServerError(w, errors.New("reference parameter cannot be empty"))
+ return
+ }
+ // Enforce the docker transport. This is just a precaution as some callers
+ // might accustomed to using the "transport:reference" notation. Using
+ // another than the "docker://" transport does not really make sense for a
+ // remote case. For loading tarballs, the load and import endpoints should
+ // be used.
+ imageRef, err := alltransports.ParseImageName(query.Reference)
+ if err == nil && imageRef.Transport().Name() != docker.Transport.Name() {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Errorf("reference %q must be a docker reference", query.Reference))
+ return
+ } else if err != nil {
+ origErr := err
+ imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s://%s", docker.Transport.Name(), query.Reference))
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(origErr, "reference %q must be a docker reference", query.Reference))
+ return
+ }
+ }
+
+ // all-tags doesn't work with a tagged reference, so let's check early
+ namedRef, err := reference.Parse(query.Reference)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "error parsing reference %q", query.Reference))
+ return
+ }
+ if _, isTagged := namedRef.(reference.Tagged); isTagged && query.AllTags {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Errorf("reference %q must not have a tag for all-tags", query.Reference))
+ return
+ }
+
+ var registryCreds *types.DockerAuthConfig
+ if len(query.Credentials) != 0 {
+ creds, err := util.ParseRegistryCreds(query.Credentials)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "error parsing credentials %q", query.Credentials))
+ return
+ }
+ registryCreds = creds
+ }
+
+ // Setup the registry options
+ dockerRegistryOptions := image.DockerRegistryOptions{
+ DockerRegistryCreds: registryCreds,
+ OSChoice: query.OverrideOS,
+ ArchitectureChoice: query.OverrideArch,
+ }
+ if query.TLSVerify {
+ dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
+ // Prepare the images we want to pull
+ imagesToPull := []string{}
+ res := []handlers.LibpodImagesPullReport{}
+ imageName := namedRef.String()
+
+ if !query.AllTags {
+ imagesToPull = append(imagesToPull, imageName)
+ } else {
+ systemContext := image.GetSystemContext("", "", false)
+ tags, err := docker.GetRepositoryTags(context.Background(), systemContext, imageRef)
+ if err != nil {
+ utils.InternalServerError(w, errors.Wrap(err, "error getting repository tags"))
+ return
+ }
+ for _, tag := range tags {
+ imagesToPull = append(imagesToPull, fmt.Sprintf("%s:%s", imageName, tag))
+ }
+ }
+
+ // Finally pull the images
+ for _, img := range imagesToPull {
+ newImage, err := runtime.ImageRuntime().New(
+ context.Background(),
+ img,
+ "",
+ "",
+ os.Stderr,
+ &dockerRegistryOptions,
+ image.SigningOptions{},
+ nil,
+ util.PullImageAlways)
+ if err != nil {
+ utils.InternalServerError(w, errors.Wrapf(err, "error pulling image %q", query.Reference))
+ return
+ }
+ res = append(res, handlers.LibpodImagesPullReport{ID: newImage.ID()})
+ }
+
+ utils.WriteResponse(w, http.StatusOK, res)
}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 091368985..e9297d91b 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -91,7 +91,11 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
pod, err := runtime.NewPod(r.Context(), options...)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
+ http_code := http.StatusInternalServerError
+ if errors.Cause(err) == define.ErrPodExists {
+ http_code = http.StatusConflict
+ }
+ utils.Error(w, "Something went wrong.", http_code, err)
return
}
utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: pod.CgroupParent()})
@@ -198,8 +202,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
}
}
if allContainersStopped {
- alreadyStopped := errors.Errorf("pod %s is already stopped", pod.ID())
- utils.Error(w, "Something went wrong", http.StatusNotModified, alreadyStopped)
+ utils.WriteResponse(w, http.StatusNotModified, "")
return
}
@@ -245,8 +248,7 @@ func PodStart(w http.ResponseWriter, r *http.Request) {
}
}
if allContainersRunning {
- alreadyRunning := errors.Errorf("pod %s is already running", pod.ID())
- utils.Error(w, "Something went wrong", http.StatusNotModified, alreadyRunning)
+ utils.WriteResponse(w, http.StatusNotModified, "")
return
}
if _, err := pod.Start(r.Context()); err != nil {
@@ -409,5 +411,5 @@ func PodExists(w http.ResponseWriter, r *http.Request) {
utils.PodNotFound(w, name, err)
return
}
- utils.WriteResponse(w, http.StatusOK, "")
+ utils.WriteResponse(w, http.StatusNoContent, "")
}
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 6169adb18..f5d9f9ad5 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -33,6 +33,18 @@ type ContainerConfig struct {
dockerContainer.Config
}
+type LibpodImagesLoadReport struct {
+ ID string `json:"id"`
+}
+
+type LibpodImagesImportReport struct {
+ ID string `json:"id"`
+}
+
+type LibpodImagesPullReport struct {
+ ID string `json:"id"`
+}
+
type ImageSummary struct {
docker.ImageSummary
CreatedTime time.Time `json:"CreatedTime,omitempty"`
@@ -49,21 +61,6 @@ type LibpodContainersPruneReport struct {
PruneError string `json:"error"`
}
-type LibpodImagesLoadReport struct {
- ID string `json:"id"`
- RepoTags []string `json:"repoTags"`
-}
-
-type LibpodImagesImportReport struct {
- ID string `json:"id"`
- RepoTags []string `json:"repoTags"`
-}
-
-type LibpodImagesPullReport struct {
- ID string `json:"id"`
- RepoTags []string `json:"repoTags"`
-}
-
type Info struct {
docker.Info
BuildahVersion string
diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go
index 970f93791..44bcc794c 100644
--- a/pkg/api/handlers/utils/handler.go
+++ b/pkg/api/handlers/utils/handler.go
@@ -23,6 +23,14 @@ func IsLibpodRequest(r *http.Request) bool {
// WriteResponse encodes the given value as JSON or string and renders it for http client
func WriteResponse(w http.ResponseWriter, code int, value interface{}) {
+ // RFC2616 explicitly states that the following status codes "MUST NOT
+ // include a message-body":
+ switch code {
+ case http.StatusNoContent, http.StatusNotModified: // 204, 304
+ w.WriteHeader(code)
+ return
+ }
+
switch v := value.(type) {
case string:
w.Header().Set("Content-Type", "text/plain; charset=us-ascii")
diff --git a/pkg/api/server/register_events.go b/pkg/api/server/register_events.go
index a32244f4d..090f66323 100644
--- a/pkg/api/server/register_events.go
+++ b/pkg/api/server/register_events.go
@@ -29,7 +29,7 @@ func (s *APIServer) RegisterEventsHandlers(r *mux.Router) error {
// description: JSON encoded map[string][]string of constraints
// responses:
// 200:
- // $ref: "#/responses/ok"
+ // description: returns a string of json data describing an event
// 500:
// "$ref": "#/responses/InternalError"
r.Handle(VersionedPath("/events"), APIHandler(s.Context, handlers.GetEvents))
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 4a46b6ee6..f082c5fec 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -639,12 +639,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Load an image (oci-archive or docker-archive) stream.
// parameters:
// - in: query
- // name: change
- // description: "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR. JSON encoded string"
- // type: string
- // - in: query
- // name: message
- // description: Set commit message for imported image
+ // name: reference
+ // description: "Optional Name[:TAG] for the image"
// type: string
// - in: formData
// name: upload
@@ -656,6 +652,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// responses:
// 200:
// $ref: "#/responses/DocsLibpodImagesLoadResponse"
+ // 400:
+ // $ref: "#/responses/BadParamError"
// 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/load"), APIHandler(s.Context, libpod.ImagesLoad)).Methods(http.MethodPost)
@@ -667,17 +665,23 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Import a previously exported tarball as an image.
// parameters:
// - in: query
- // name: change
- // description: "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR. JSON encoded string"
- // type: string
+ // name: changes
+ // description: "Apply the following possible instructions to the created image: CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR. JSON encoded string"
+ // type: array
+ // items:
+ // type: string
// - in: query
// name: message
// description: Set commit message for imported image
// type: string
// - in: query
+ // name: reference
+ // description: "Optional Name[:TAG] for the image"
+ // type: string
+ // - in: query
// name: url
- // description: Specify a URL instead of a tarball
- // type: boolean
+ // description: Load image from the specified URL
+ // type: string
// - in: formData
// name: upload
// type: file
@@ -688,34 +692,50 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// responses:
// 200:
// $ref: "#/responses/DocsLibpodImagesImportResponse"
+ // 400:
+ // $ref: "#/responses/BadParamError"
// 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/import"), APIHandler(s.Context, libpod.ImagesImport)).Methods(http.MethodPost)
- // swagger:operation GET /libpod/images/pull libpod libpodImagesPull
+ // swagger:operation POST /libpod/images/pull libpod libpodImagesPull
// ---
// tags:
// - images
- // summary: Import image
- // description: Import a previosly exported image as a tarball.
+ // summary: Pull images
+ // description: Pull one or more images from a container registry.
// parameters:
- // - in: query
- // name: reference
- // description: Mandatory reference to the image (e.g., quay.io/image/name:tag)/
- // type: string
- // - in: query
- // name: credentials
- // description: username:password for the registry.
- // type: string
- // - in: query
- // name: tls-verify
- // description: Require TLS verification.
- // type: boolean
- // default: true
+ // - in: query
+ // name: reference
+ // description: "Mandatory reference to the image (e.g., quay.io/image/name:tag)"
+ // type: string
+ // - in: query
+ // name: credentials
+ // description: "username:password for the registry"
+ // type: string
+ // - in: query
+ // name: overrideOS
+ // description: Pull image for the specified operating system.
+ // type: string
+ // - in: query
+ // name: overrideArch
+ // description: Pull image for the specified architecture.
+ // type: string
+ // - in: query
+ // name: tlsVerify
+ // description: Require TLS verification.
+ // type: boolean
+ // default: true
+ // - in: query
+ // name: allTags
+ // description: Pull all tagged images in the repository.
+ // type: boolean
// produces:
// - application/json
// responses:
// 200:
// $ref: "#/responses/DocsLibpodImagesPullResponse"
+ // 400:
+ // $ref: "#/responses/BadParamError"
// 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/pull"), APIHandler(s.Context, libpod.ImagesPull)).Methods(http.MethodPost)
diff --git a/pkg/api/server/register_pods.go b/pkg/api/server/register_pods.go
index 5c7b51871..974568d47 100644
--- a/pkg/api/server/register_pods.go
+++ b/pkg/api/server/register_pods.go
@@ -41,6 +41,8 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// type: string
// 400:
// $ref: "#/responses/BadParamError"
+ // 409:
+ // description: pod already exists
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/prune"), APIHandler(s.Context, libpod.PodPrune)).Methods(http.MethodPost)
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 7bb0f5481..87b11b716 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -106,6 +106,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
server.RegisterContainersHandlers,
server.RegisterDistributionHandlers,
server.registerExecHandlers,
+ server.RegisterEventsHandlers,
server.registerHealthCheckHandlers,
server.registerImagesHandlers,
server.registerInfoHandlers,