summaryrefslogtreecommitdiff
path: root/pkg/api/server
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api/server')
-rw-r--r--pkg/api/server/handler_api.go37
-rw-r--r--pkg/api/server/register_auth.go11
-rw-r--r--pkg/api/server/register_containers.go889
-rw-r--r--pkg/api/server/register_distribution.go11
-rw-r--r--pkg/api/server/register_events.go32
-rw-r--r--pkg/api/server/register_healthcheck.go13
-rw-r--r--pkg/api/server/register_images.go663
-rw-r--r--pkg/api/server/register_info.go28
-rw-r--r--pkg/api/server/register_monitor.go11
-rw-r--r--pkg/api/server/register_ping.go17
-rw-r--r--pkg/api/server/register_plugins.go11
-rw-r--r--pkg/api/server/register_pods.go24
-rw-r--r--pkg/api/server/register_swarm.go27
-rw-r--r--pkg/api/server/register_system.go11
-rw-r--r--pkg/api/server/register_version.go12
-rw-r--r--pkg/api/server/register_volumes.go17
-rw-r--r--pkg/api/server/server.go189
17 files changed, 2003 insertions, 0 deletions
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
new file mode 100644
index 000000000..4b93998ee
--- /dev/null
+++ b/pkg/api/server/handler_api.go
@@ -0,0 +1,37 @@
+package server
+
+import (
+ "context"
+ "net/http"
+
+ log "github.com/sirupsen/logrus"
+)
+
+// APIHandler is a wrapper to enhance HandlerFunc's and remove redundant code
+func APIHandler(ctx context.Context, h http.HandlerFunc) http.HandlerFunc {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ log.Debugf("APIHandler -- Method: %s URL: %s", r.Method, r.URL.String())
+ if err := r.ParseForm(); err != nil {
+ log.Infof("Failed Request: unable to parse form: %q", err)
+ }
+
+ // TODO: Use ConnContext when ported to go 1.13
+ c := context.WithValue(r.Context(), "decoder", ctx.Value("decoder"))
+ c = context.WithValue(c, "runtime", ctx.Value("runtime"))
+ c = context.WithValue(c, "shutdownFunc", ctx.Value("shutdownFunc"))
+ r = r.WithContext(c)
+
+ h(w, r)
+
+ shutdownFunc := r.Context().Value("shutdownFunc").(func() error)
+ if err := shutdownFunc(); err != nil {
+ log.Errorf("Failed to shutdown Server in APIHandler(): %s", err.Error())
+ }
+ })
+}
+
+// VersionedPath prepends the version parsing code
+// any handler may override this default when registering URL(s)
+func VersionedPath(p string) string {
+ return "/v{version:[0-9][0-9.]*}" + p
+}
diff --git a/pkg/api/server/register_auth.go b/pkg/api/server/register_auth.go
new file mode 100644
index 000000000..9f312683d
--- /dev/null
+++ b/pkg/api/server/register_auth.go
@@ -0,0 +1,11 @@
+package server
+
+import (
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) RegisterAuthHandlers(r *mux.Router) error {
+ r.Handle(VersionedPath("/auth"), APIHandler(s.Context, handlers.UnsupportedHandler))
+ return nil
+}
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
new file mode 100644
index 000000000..7d80f2f67
--- /dev/null
+++ b/pkg/api/server/register_containers.go
@@ -0,0 +1,889 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/containers/libpod/pkg/api/handlers/generic"
+ "github.com/containers/libpod/pkg/api/handlers/libpod"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
+ // swagger:operation POST /containers/create containers createContainer
+ //
+ // Create a container
+ //
+ // ---
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: query
+ // name: name
+ // type: string
+ // description: container name
+ // responses:
+ // '201':
+ // schema:
+ // items:
+ // "$ref": "#/ctrCreateResponse"
+ // '400':
+ // description: bad parameter
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/create"), APIHandler(s.Context, generic.CreateContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/json containers listContainers
+ //
+ // List containers
+ //
+ // ---
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // type: array
+ // items:
+ // "$ref": "#/types/Container"
+ // '400':
+ // description: bad parameter
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/json"), APIHandler(s.Context, generic.ListContainers)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/prune containers pruneContainers
+ //
+ // Prune unused containers
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: map[string][]string
+ // description: something
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // "$ref": "#/types/ContainerPruneReport"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/prune"), APIHandler(s.Context, generic.PruneContainers)).Methods(http.MethodPost)
+ // swagger:operation DELETE /containers/{nameOrID} containers removeContainer
+ //
+ // Delete container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: force
+ // type: bool
+ // description: need something
+ // - in: query
+ // name: v
+ // type: bool
+ // description: need something
+ // - in: query
+ // name: link
+ // type: bool
+ // description: not supported
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // type: array
+ // items:
+ // "$ref": "#/types/Container"
+ // '400':
+ // description: bad parameter
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}"), APIHandler(s.Context, generic.RemoveContainer)).Methods(http.MethodDelete)
+ // swagger:operation GET /containers/{nameOrID}/json containers getContainer
+ //
+ // Inspect Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/types/ContainerJSON"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/json"), APIHandler(s.Context, generic.GetContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{nameOrID}/kill containers killContainer
+ //
+ // Kill Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: signal
+ // type: int
+ // description: signal to be sent to container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/kill"), APIHandler(s.Context, generic.KillContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{nameOrID}/logs containers LogsFromContainer
+ //
+ // Get logs from container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: follow
+ // type: bool
+ // description: needs description
+ // - in: query
+ // name: stdout
+ // type: bool
+ // description: needs description
+ // - in: query
+ // name: stderr
+ // type: bool
+ // description: needs description
+ // - in: query
+ // name: since
+ // type: string
+ // description: needs description
+ // - in: query
+ // name: until
+ // type: string
+ // description: needs description
+ // - in: query
+ // name: timestamps
+ // type: bool
+ // description: needs description
+ // - in: query
+ // name: tail
+ // type: string
+ // description: needs description
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/logs"), APIHandler(s.Context, generic.LogsFromContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{nameOrID}/pause containers pauseContainer
+ //
+ // Pause Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/pause"), APIHandler(s.Context, handlers.PauseContainer)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/rename"), APIHandler(s.Context, handlers.UnsupportedHandler)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{nameOrID}/restart containers restartContainer
+ //
+ // Restart Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: t
+ // type: int
+ // description: timeout before sending kill signal to container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/restart"), APIHandler(s.Context, handlers.RestartContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{nameOrID}/start containers startContainer
+ //
+ // Start a container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: detachKeys
+ // type: string
+ // description: needs description
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '304':
+ // description: container already started
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/start"), APIHandler(s.Context, handlers.StartContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{nameOrID}/stats containers statsContainer
+ //
+ // Get stats for a contrainer
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: stream
+ // type: bool
+ // description: needs description
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: no error
+ // schema:
+ // "ref": "#/handler/stats"
+ // '304':
+ // description: container already started
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/stats"), APIHandler(s.Context, generic.StatsContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{nameOrID}/stop containers stopContainer
+ //
+ // Stop a container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: t
+ // type: int
+ // description: number of seconds to wait before killing container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '304':
+ // description: container already stopped
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/stop"), APIHandler(s.Context, handlers.StopContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{nameOrID}/top containers topContainer
+ //
+ // List processes running inside a container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: ps_args
+ // type: string
+ // description: arguments to pass to ps such as aux
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: no error
+ // schema:
+ // "ref": "#/types/ContainerTopBody"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{nameOrID}/unpause containers unpauseContainer
+ //
+ // Unpause Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/unpause"), APIHandler(s.Context, handlers.UnpauseContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{nameOrID}/wait containers waitContainer
+ //
+ // Wait on a container to exit
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: condition
+ // type: string
+ // description: Wait until the container reaches the given condition
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/wait"), APIHandler(s.Context, generic.WaitContainer)).Methods(http.MethodPost)
+
+ /*
+ libpod endpoints
+ */
+
+ r.HandleFunc(VersionedPath("/libpod/containers/create"), APIHandler(s.Context, libpod.CreateContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /libpod/containers/json containers listContainers
+ //
+ // List containers
+ //
+ // ---
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // type: array
+ // items:
+ // "$ref": "#/shared/GetPsContainerOutput"
+ // '400':
+ // description: bad parameter
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/json"), APIHandler(s.Context, libpod.ListContainers)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/prune containers pruneContainers
+ //
+ // Prune unused containers
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: force
+ // type: bool
+ // description: something
+ // - in: query
+ // name: filters
+ // type: map[string][]string
+ // description: something
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // "$ref": "#/types/ContainerPruneReport"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/prune"), APIHandler(s.Context, libpod.PruneContainers)).Methods(http.MethodPost)
+ // swagger:operation GET /libpod/containers/showmounted containers showMounterContainers
+ //
+ // Show mounted containers
+ //
+ // ---
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // "$ref": "TBD"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/showmounted"), APIHandler(s.Context, libpod.ShowMountedContainers)).Methods(http.MethodGet)
+ // swagger:operation DELETE /libpod/containers/json containers removeContainer
+ //
+ // Delete container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: force
+ // type: bool
+ // description: need something
+ // - in: query
+ // name: v
+ // type: bool
+ // description: need something
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // type: array
+ // items:
+ // "$ref": "#/types/Container"
+ // '400':
+ // description: bad parameter
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}"), APIHandler(s.Context, libpod.RemoveContainer)).Methods(http.MethodDelete)
+ // swagger:operation GET /libpod/containers/{nameOrID}/json containers getContainer
+ //
+ // Inspect Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: size
+ // type: bool
+ // description: display filesystem usage
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#InspectContainerData"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/json"), APIHandler(s.Context, libpod.GetContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{nameOrID}/kill containers killContainer
+ //
+ // Kill Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: signal
+ // type: int
+ // default: 15
+ // description: signal to be sent to container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/kill"), APIHandler(s.Context, libpod.KillContainer)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/containers/{nameOrID}/mount containers mountContainer
+ //
+ // Mount a container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "string"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/mount"), APIHandler(s.Context, libpod.LogsFromContainer)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/logs"), APIHandler(s.Context, libpod.LogsFromContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{nameOrID}/pause containers pauseContainer
+ //
+ // Pause Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/pause"), APIHandler(s.Context, handlers.PauseContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{nameOrID}/restart containers restartContainer
+ //
+ // Restart Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: t
+ // type: int
+ // description: timeout before sending kill signal to container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/restart"), APIHandler(s.Context, handlers.RestartContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{nameOrID}/start containers startContainer
+ //
+ // Start a container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: detachKeys
+ // type: string
+ // description: needs description
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '304':
+ // description: container already started
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/start"), APIHandler(s.Context, handlers.StartContainer)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/stats"), APIHandler(s.Context, libpod.StatsContainer)).Methods(http.MethodGet)
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{nameOrID}/unpause containers unpauseContainer
+ //
+ // Unpause Container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/unpause"), APIHandler(s.Context, handlers.UnpauseContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{nameOrID}/wait containers waitContainer
+ //
+ // Wait on a container to exit
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: condition
+ // type: string
+ // description: Wait until the container reaches the given condition
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/wait"), APIHandler(s.Context, libpod.WaitContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{nameOrID}/exists containers containerExists
+ //
+ // Check if container exists
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // schema:
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/exists"), APIHandler(s.Context, libpod.ContainerExists)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{nameOrID}/stop containers stopContainer
+ //
+ // Stop a container
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: t
+ // type: int
+ // description: number of seconds to wait before killing container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '304':
+ // description: container already stopped
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such container
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/stop"), APIHandler(s.Context, handlers.StopContainer)).Methods(http.MethodPost)
+ return nil
+}
diff --git a/pkg/api/server/register_distribution.go b/pkg/api/server/register_distribution.go
new file mode 100644
index 000000000..23820b4a7
--- /dev/null
+++ b/pkg/api/server/register_distribution.go
@@ -0,0 +1,11 @@
+package server
+
+import (
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) RegisterDistributionHandlers(r *mux.Router) error {
+ r.HandleFunc(VersionedPath("/distribution/{name:..*}/json"), handlers.UnsupportedHandler)
+ return nil
+}
diff --git a/pkg/api/server/register_events.go b/pkg/api/server/register_events.go
new file mode 100644
index 000000000..d764fdbb4
--- /dev/null
+++ b/pkg/api/server/register_events.go
@@ -0,0 +1,32 @@
+package server
+
+import (
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) RegisterEventsHandlers(r *mux.Router) error {
+ // swagger:operation GET /events system getEvents
+ // ---
+ // summary: Returns events filtered on query parameters
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: since
+ // in: query
+ // description: start streaming events from this time
+ // - name: until
+ // in: query
+ // description: stop streaming events later than this
+ // - name: filters
+ // in: query
+ // description: JSON encoded map[string][]string of constraints
+ // responses:
+ // "200":
+ // description: OK
+ // "500":
+ // description: Failed
+ // "$ref": "#/types/errorModel"
+ r.Handle(VersionedPath("/events"), APIHandler(s.Context, handlers.GetEvents))
+ return nil
+}
diff --git a/pkg/api/server/register_healthcheck.go b/pkg/api/server/register_healthcheck.go
new file mode 100644
index 000000000..e4cc145d5
--- /dev/null
+++ b/pkg/api/server/register_healthcheck.go
@@ -0,0 +1,13 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers/libpod"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerHealthCheckHandlers(r *mux.Router) error {
+ r.Handle(VersionedPath("/libpod/containers/{name:..*}/runhealthcheck"), APIHandler(s.Context, libpod.RunHealthCheck)).Methods(http.MethodGet)
+ return nil
+}
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
new file mode 100644
index 000000000..4ad4409df
--- /dev/null
+++ b/pkg/api/server/register_images.go
@@ -0,0 +1,663 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/containers/libpod/pkg/api/handlers/generic"
+ "github.com/containers/libpod/pkg/api/handlers/libpod"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
+ // swagger:operation POST /images/create images createImage
+ //
+ // Create an image from an image
+ //
+ // ---
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: query
+ // name: fromImage
+ // type: string
+ // description: needs description
+ // - in: query
+ // name: tag
+ // type: string
+ // description: needs description
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "TBD"
+ // '404':
+ // description: repo or image does not exist
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}")
+ // swagger:operation POST /images/create images createImage
+ //
+ // Create an image from Source
+ //
+ // ---
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: query
+ // name: fromSrc
+ // type: string
+ // description: needs description
+ // - in: query
+ // name: changes
+ // type: TBD
+ // description: needs description
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "TBD"
+ // '404':
+ // description: repo or image does not exist
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromSrc)).Methods(http.MethodPost).Queries("fromSrc", "{fromSrc}")
+ // swagger:operation GET /images/json images listImages
+ //
+ // List Images
+ //
+ // ---
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/types/ImageSummary"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/json"), APIHandler(s.Context, generic.GetImages)).Methods(http.MethodGet)
+ // swagger:operation POST /images/load images loadImage
+ //
+ // Import image
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: quiet
+ // type: bool
+ // description: not supported
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/types/ImageSummary"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/load"), APIHandler(s.Context, handlers.LoadImage)).Methods(http.MethodPost)
+ // swagger:operation POST /images/prune images pruneImages
+ //
+ // Prune unused images
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: map[string][]string
+ // description: not supported
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/ImageDeleteResponse"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/prune"), APIHandler(s.Context, generic.PruneImages)).Methods(http.MethodPost)
+ // swagger:operation GET /images/search images searchImages
+ //
+ // Search images
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: term
+ // type: string
+ // description: term to search
+ // - in: query
+ // name: limit
+ // type: int
+ // description: maximum number of results
+ // - in: query
+ // name: filters
+ // type: map[string][]string
+ // description: TBD
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/images.SearchResult"
+ // description: no error
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/search"), APIHandler(s.Context, handlers.SearchImages)).Methods(http.MethodGet)
+ // swagger:operation DELETE /images/{nameOrID} images removeImage
+ //
+ // Remove Image
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: force
+ // type: bool
+ // description: remove the image even if used by containers or has other tags
+ // - in: query
+ // name: noprune
+ // type: bool
+ // description: not supported
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "TBD"
+ // description: no error
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/{name:..*}"), APIHandler(s.Context, handlers.RemoveImage)).Methods(http.MethodDelete)
+ // swagger:operation GET /images/{nameOrID}/get images exportImage
+ //
+ // Export an image
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "TBD"
+ // description: no error
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/{name:..*}/get"), APIHandler(s.Context, generic.ExportImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/{nameOrID}/history images imageHistory
+ //
+ // History of an image
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/types/HistoryResponse"
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/{name:..*}/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/{nameOrID}/json images inspectImage
+ //
+ // Inspect an image
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/types/imageInspect"
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/{name:..*}/json"), APIHandler(s.Context, generic.GetImage))
+ // swagger:operation POST /images/{nameOrID}/tag images tagImage
+ //
+ // Tag an image
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: repo
+ // type: string
+ // description: the repository to tag in
+ // - in: query
+ // name: tag
+ // type: string
+ // description: the name of the new tag
+ // produces:
+ // - application/json
+ // responses:
+ // '201':
+ // description: no error
+ // '400':
+ // description: bad parameter
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/images/{name:..*}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
+ // swagger:operation POST /commit/ commit commitContainer
+ //
+ // Create a new image from a container
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: container
+ // type: string
+ // description: the name or ID of a container
+ // - in: query
+ // name: repo
+ // type: string
+ // description: the repository name for the created image
+ // - in: query
+ // name: tag
+ // type: string
+ // description: tag name for the created image
+ // - in: query
+ // name: comment
+ // type: string
+ // description: commit message
+ // - in: query
+ // name: author
+ // type: string
+ // description: author of the image
+ // - in: query
+ // name: pause
+ // type: bool
+ // description: pause the container before committing it
+ // - in: query
+ // name: changes
+ // type: string
+ // description: instructions to apply while committing in Dockerfile format
+ // produces:
+ // - application/json
+ // responses:
+ // '201':
+ // description: no error
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/commit"), APIHandler(s.Context, generic.CommitContainer)).Methods(http.MethodPost)
+
+ /*
+ libpod endpoints
+ */
+
+ // swagger:operation POST /libpod/images/{nameOrID}/exists images imageExists
+ //
+ // Check if image exists in local store
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: query
+ // name: fromImage
+ // type: string
+ // description: needs description
+ // - in: query
+ // name: tag
+ // type: string
+ // description: needs description
+ // responses:
+ // '204':
+ // description: image exists
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/{name:..*}/exists"), APIHandler(s.Context, libpod.ImageExists))
+ r.Handle(VersionedPath("/libpod/images/{name:..*}/tree"), APIHandler(s.Context, libpod.ImageTree))
+ // swagger:operation GET /libpod/images/{nameOrID}/history images imageHistory
+ //
+ // History of an image
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/types/HistoryResponse"
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/images/json images listImages
+ //
+ // List Images
+ //
+ // ---
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/types/ImageSummary"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/json"), APIHandler(s.Context, libpod.GetImages)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/images/load images loadImage
+ //
+ // Import image
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: quiet
+ // type: bool
+ // description: not supported
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/types/ImageSummary"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/load"), APIHandler(s.Context, handlers.LoadImage)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/images/prune images pruneImages
+ //
+ // Prune unused images
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: map[string][]string
+ // description: image filters
+ // - in: query
+ // name: all
+ // type: bool
+ // description: prune all images
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/ImageDeleteResponse"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/prune"), APIHandler(s.Context, libpod.PruneImages)).Methods(http.MethodPost)
+ // swagger:operation GET /libpod/images/search images searchImages
+ //
+ // Search images
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: term
+ // type: string
+ // description: term to search
+ // - in: query
+ // name: limit
+ // type: int
+ // description: maximum number of results
+ // - in: query
+ // name: filters
+ // type: map[string][]string
+ // description: TBD
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/images.SearchResult"
+ // description: no error
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/search"), APIHandler(s.Context, handlers.SearchImages)).Methods(http.MethodGet)
+ // swagger:operation DELETE /libpod/images/{nameOrID} images removeImage
+ //
+ // Remove Image
+ //
+ // ---
+ // parameters:
+ // - in: query
+ // name: force
+ // type: bool
+ // description: remove the image even if used by containers or has other tags
+ // - in: query
+ // name: noprune
+ // type: bool
+ // description: not supported
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "TBD"
+ // description: no error
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/{name:..*}"), APIHandler(s.Context, handlers.RemoveImage)).Methods(http.MethodDelete)
+ // swagger:operation GET /libpod/images/{nameOrID}/get images exportImage
+ //
+ // Export an image
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: format
+ // type: string
+ // description: format for exported image
+ // - in: query
+ // name: compress
+ // type: bool
+ // description: use compression on image
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "TBD"
+ // description: no error
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/{name:..*}/get"), APIHandler(s.Context, libpod.ExportImage)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/images/{nameOrID}/json images inspectImage
+ //
+ // Inspect an image
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // "$ref": "#/inspect/ImageData"
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/{name:..*}/json"), APIHandler(s.Context, libpod.GetImage))
+ // swagger:operation POST /libpod/images/{nameOrID}/tag images tagImage
+ //
+ // Tag an image
+ //
+ // ---
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: repo
+ // type: string
+ // description: the repository to tag in
+ // - in: query
+ // name: tag
+ // type: string
+ // description: the name of the new tag
+ // produces:
+ // - application/json
+ // responses:
+ // '201':
+ // description: no error
+ // '400':
+ // description: bad parameter
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '404':
+ // description: no such image
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '409':
+ // description: conflict
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/libpod/images/{name:..*}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
+
+ r.Handle(VersionedPath("/build"), APIHandler(s.Context, handlers.BuildImage)).Methods(http.MethodPost)
+ return nil
+}
diff --git a/pkg/api/server/register_info.go b/pkg/api/server/register_info.go
new file mode 100644
index 000000000..797158553
--- /dev/null
+++ b/pkg/api/server/register_info.go
@@ -0,0 +1,28 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers/generic"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerInfoHandlers(r *mux.Router) error {
+ // swagger:operation GET /info libpod getInfo
+ //
+ // Returns information on the system and libpod configuration
+ //
+ // ---
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // "$ref": "#/types/Info"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // "$ref": "#/types/ErrorModel"
+ r.Handle(VersionedPath("/info"), APIHandler(s.Context, generic.GetInfo)).Methods(http.MethodGet)
+ return nil
+}
diff --git a/pkg/api/server/register_monitor.go b/pkg/api/server/register_monitor.go
new file mode 100644
index 000000000..e6c235419
--- /dev/null
+++ b/pkg/api/server/register_monitor.go
@@ -0,0 +1,11 @@
+package server
+
+import (
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) RegisterMonitorHandlers(r *mux.Router) error {
+ r.Handle(VersionedPath("/monitor"), APIHandler(s.Context, handlers.UnsupportedHandler))
+ return nil
+}
diff --git a/pkg/api/server/register_ping.go b/pkg/api/server/register_ping.go
new file mode 100644
index 000000000..4956f9822
--- /dev/null
+++ b/pkg/api/server/register_ping.go
@@ -0,0 +1,17 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers/generic"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerPingHandlers(r *mux.Router) error {
+ r.Handle("/_ping", APIHandler(s.Context, generic.PingGET)).Methods(http.MethodGet)
+ r.Handle("/_ping", APIHandler(s.Context, generic.PingHEAD)).Methods("HEAD")
+
+ // libpod
+ r.Handle("/libpod/_ping", APIHandler(s.Context, generic.PingGET)).Methods(http.MethodGet)
+ return nil
+}
diff --git a/pkg/api/server/register_plugins.go b/pkg/api/server/register_plugins.go
new file mode 100644
index 000000000..7fd6b9c4c
--- /dev/null
+++ b/pkg/api/server/register_plugins.go
@@ -0,0 +1,11 @@
+package server
+
+import (
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) RegisterPluginsHandlers(r *mux.Router) error {
+ r.Handle(VersionedPath("/plugins"), APIHandler(s.Context, handlers.UnsupportedHandler))
+ return nil
+}
diff --git a/pkg/api/server/register_pods.go b/pkg/api/server/register_pods.go
new file mode 100644
index 000000000..b5915da98
--- /dev/null
+++ b/pkg/api/server/register_pods.go
@@ -0,0 +1,24 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers/libpod"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
+ r.Handle(VersionedPath("/libpod/pods/json"), APIHandler(s.Context, libpod.Pods)).Methods(http.MethodGet)
+ r.Handle(VersionedPath("/libpod/pods/create"), APIHandler(s.Context, libpod.PodCreate)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/pods/prune"), APIHandler(s.Context, libpod.PodPrune)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}"), APIHandler(s.Context, libpod.PodDelete)).Methods(http.MethodDelete)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}"), APIHandler(s.Context, libpod.PodInspect)).Methods(http.MethodGet)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/exists"), APIHandler(s.Context, libpod.PodExists)).Methods(http.MethodGet)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/kill"), APIHandler(s.Context, libpod.PodKill)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/pause"), APIHandler(s.Context, libpod.PodPause)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/restart"), APIHandler(s.Context, libpod.PodRestart)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/start"), APIHandler(s.Context, libpod.PodStart)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/stop"), APIHandler(s.Context, libpod.PodStop)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/unpause"), APIHandler(s.Context, libpod.PodUnpause)).Methods(http.MethodPost)
+ return nil
+}
diff --git a/pkg/api/server/register_swarm.go b/pkg/api/server/register_swarm.go
new file mode 100644
index 000000000..61c0b2d83
--- /dev/null
+++ b/pkg/api/server/register_swarm.go
@@ -0,0 +1,27 @@
+package server
+
+import (
+ "errors"
+ "github.com/containers/libpod/pkg/api/handlers/utils"
+ "net/http"
+
+ "github.com/gorilla/mux"
+ "github.com/sirupsen/logrus"
+)
+
+func (s *APIServer) RegisterSwarmHandlers(r *mux.Router) error {
+ r.PathPrefix("/v{version:[0-9.]+}/configs/").HandlerFunc(noSwarm)
+ r.PathPrefix("/v{version:[0-9.]+}/nodes/").HandlerFunc(noSwarm)
+ r.PathPrefix("/v{version:[0-9.]+}/secrets/").HandlerFunc(noSwarm)
+ r.PathPrefix("/v{version:[0-9.]+}/services/").HandlerFunc(noSwarm)
+ r.PathPrefix("/v{version:[0-9.]+}/swarm/").HandlerFunc(noSwarm)
+ r.PathPrefix("/v{version:[0-9.]+}/tasks/").HandlerFunc(noSwarm)
+ return nil
+}
+
+// noSwarm returns http.StatusServiceUnavailable rather than something like http.StatusInternalServerError,
+// this allows the client to decide if they still can talk to us
+func noSwarm(w http.ResponseWriter, r *http.Request) {
+ logrus.Errorf("%s is not a podman supported service", r.URL.String())
+ utils.Error(w, "node is not part of a swarm", http.StatusServiceUnavailable, errors.New("Podman does not support service: "+r.URL.String()))
+}
diff --git a/pkg/api/server/register_system.go b/pkg/api/server/register_system.go
new file mode 100644
index 000000000..f0eaeffd2
--- /dev/null
+++ b/pkg/api/server/register_system.go
@@ -0,0 +1,11 @@
+package server
+
+import (
+ "github.com/containers/libpod/pkg/api/handlers/generic"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerSystemHandlers(r *mux.Router) error {
+ r.Handle(VersionedPath("/system/df"), APIHandler(s.Context, generic.GetDiskUsage))
+ return nil
+}
diff --git a/pkg/api/server/register_version.go b/pkg/api/server/register_version.go
new file mode 100644
index 000000000..94216b1b6
--- /dev/null
+++ b/pkg/api/server/register_version.go
@@ -0,0 +1,12 @@
+package server
+
+import (
+ "github.com/containers/libpod/pkg/api/handlers/generic"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerVersionHandlers(r *mux.Router) error {
+ r.Handle("/version", APIHandler(s.Context, generic.VersionHandler))
+ r.Handle(VersionedPath("/version"), APIHandler(s.Context, generic.VersionHandler))
+ return nil
+}
diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go
new file mode 100644
index 000000000..3a9cf8c2d
--- /dev/null
+++ b/pkg/api/server/register_volumes.go
@@ -0,0 +1,17 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers/libpod"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerVolumeHandlers(r *mux.Router) error {
+ r.Handle("/libpod/volumes/create", APIHandler(s.Context, libpod.CreateVolume)).Methods(http.MethodPost)
+ r.Handle("/libpod/volumes/json", APIHandler(s.Context, libpod.ListVolumes)).Methods(http.MethodGet)
+ r.Handle("/libpod/volumes/prune", APIHandler(s.Context, libpod.PruneVolumes)).Methods(http.MethodPost)
+ r.Handle("/libpod/volumes/{name:..*}/json", APIHandler(s.Context, libpod.InspectVolume)).Methods(http.MethodGet)
+ r.Handle("/libpod/volumes/{name:..*}", APIHandler(s.Context, libpod.RemoveVolume)).Methods(http.MethodDelete)
+ return nil
+}
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
new file mode 100644
index 000000000..717c7a876
--- /dev/null
+++ b/pkg/api/server/server.go
@@ -0,0 +1,189 @@
+// Package serviceapi Provides a Container compatible interface.
+//
+// This documentation describes the HTTP LibPod interface
+//
+// Schemes: http, https
+// Host: podman.io
+// BasePath: /
+// Version: 0.0.1
+// License: Apache-2.0 https://opensource.org/licenses/Apache-2.0
+// Contact: Podman <podman@lists.podman.io> https://podman.io/community/
+//
+// Consumes:
+// - application/json
+// - application/x-tar
+//
+// Produces:
+// - application/json
+// - text/plain
+// - text/html
+//
+// tags:
+// - name: "Containers"
+// description: manage containers
+// - name: "Images"
+// description: manage images
+// - name: "System"
+// description: manage system resources
+//
+// swagger:meta
+package server
+
+import (
+ "context"
+ "net"
+ "net/http"
+ "os"
+ "os/signal"
+ "strings"
+ "time"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/coreos/go-systemd/activation"
+ "github.com/gorilla/mux"
+ "github.com/gorilla/schema"
+ "github.com/pkg/errors"
+ log "github.com/sirupsen/logrus"
+)
+
+type APIServer struct {
+ http.Server // Where the HTTP work happens
+ *schema.Decoder // Decoder for Query parameters to structs
+ context.Context // Context for graceful server shutdown
+ *libpod.Runtime // Where the real work happens
+ net.Listener // mux for routing HTTP API calls to libpod routines
+ context.CancelFunc // Stop APIServer
+ *time.Timer // Hold timer for sliding window
+ time.Duration // Duration of client access sliding window
+}
+
+// NewServer will create and configure a new API HTTP server
+func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
+ listeners, err := activation.Listeners()
+ if err != nil {
+ return nil, errors.Wrap(err, "Cannot retrieve file descriptors from systemd")
+ }
+ if len(listeners) != 1 {
+ return nil, errors.Errorf("Wrong number of file descriptors from systemd for socket activation (%d != 1)", len(listeners))
+ }
+
+ quit := make(chan os.Signal, 1)
+ signal.Notify(quit)
+
+ router := mux.NewRouter()
+
+ server := APIServer{
+ Server: http.Server{
+ Handler: router,
+ ReadHeaderTimeout: 20 * time.Second,
+ ReadTimeout: 20 * time.Second,
+ WriteTimeout: 2 * time.Minute,
+ },
+ Decoder: schema.NewDecoder(),
+ Context: nil,
+ Runtime: runtime,
+ Listener: listeners[0],
+ CancelFunc: nil,
+ Duration: 300 * time.Second,
+ }
+ server.Timer = time.AfterFunc(server.Duration, func() {
+ if err := server.Shutdown(); err != nil {
+ log.Errorf("unable to shutdown server: %q", err)
+ }
+ })
+
+ ctx, cancelFn := context.WithCancel(context.Background())
+
+ // TODO: Use ConnContext when ported to go 1.13
+ ctx = context.WithValue(ctx, "decoder", server.Decoder)
+ ctx = context.WithValue(ctx, "runtime", runtime)
+ ctx = context.WithValue(ctx, "shutdownFunc", server.Shutdown)
+ server.Context = ctx
+
+ server.CancelFunc = cancelFn
+ server.Decoder.IgnoreUnknownKeys(true)
+
+ router.NotFoundHandler = http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ // We can track user errors...
+ log.Infof("Failed Request: (%d:%s) for %s:'%s'", http.StatusNotFound, http.StatusText(http.StatusNotFound), r.Method, r.URL.String())
+ http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ },
+ )
+
+ for _, fn := range []func(*mux.Router) error{
+ server.RegisterAuthHandlers,
+ server.RegisterContainersHandlers,
+ server.RegisterDistributionHandlers,
+ server.registerHealthCheckHandlers,
+ server.registerImagesHandlers,
+ server.registerInfoHandlers,
+ server.RegisterMonitorHandlers,
+ server.registerPingHandlers,
+ server.RegisterPluginsHandlers,
+ server.registerPodsHandlers,
+ server.RegisterSwarmHandlers,
+ server.registerSystemHandlers,
+ server.registerVersionHandlers,
+ server.registerVolumeHandlers,
+ } {
+ if err := fn(router); err != nil {
+ return nil, err
+ }
+ }
+
+ if log.IsLevelEnabled(log.DebugLevel) {
+ router.Walk(func(route *mux.Route, r *mux.Router, ancestors []*mux.Route) error { // nolint
+ path, err := route.GetPathTemplate()
+ if err != nil {
+ path = ""
+ }
+ methods, err := route.GetMethods()
+ if err != nil {
+ methods = []string{}
+ }
+ log.Debugf("Methods: %s Path: %s", strings.Join(methods, ", "), path)
+ return nil
+ })
+ }
+
+ return &server, nil
+}
+
+// Serve starts responding to HTTP requests
+func (s *APIServer) Serve() error {
+ defer s.CancelFunc()
+
+ err := s.Server.Serve(s.Listener)
+ if err != nil && err != http.ErrServerClosed {
+ return errors.Wrap(err, "Failed to start APIServer")
+ }
+
+ return nil
+}
+
+// Shutdown is a clean shutdown waiting on existing clients
+func (s *APIServer) Shutdown() error {
+ // We're still in the sliding service window
+ if s.Timer.Stop() {
+ s.Timer.Reset(s.Duration)
+ return nil
+ }
+
+ // We've been idle for the service window, really shutdown
+ go func() {
+ err := s.Server.Shutdown(s.Context)
+ if err != nil && err != context.Canceled {
+ log.Errorf("Failed to cleanly shutdown APIServer: %s", err.Error())
+ }
+ }()
+
+ // Wait for graceful shutdown vs. just killing connections and dropping data
+ <-s.Context.Done()
+ return nil
+}
+
+// Close immediately stops responding to clients and exits
+func (s *APIServer) Close() error {
+ return s.Server.Close()
+}