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.go718
-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.go568
-rw-r--r--pkg/api/server/register_info.go24
-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.go239
-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.go77
-rw-r--r--pkg/api/server/server.go189
-rw-r--r--pkg/api/server/swagger.go138
18 files changed, 2146 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..711aecc84
--- /dev/null
+++ b/pkg/api/server/register_containers.go
@@ -0,0 +1,718 @@
+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
+ // ---
+ // summary: Create a container
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: query
+ // name: name
+ // type: string
+ // description: container name
+ // responses:
+ // '201':
+ // $ref: "#/responses/ContainerCreateResponse"
+ // '400':
+ // "$ref": "#/responses/BadParamError"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '409':
+ // "$ref": "#/responses/ConflictError"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/create"), APIHandler(s.Context, generic.CreateContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/json containers listContainers
+ // ---
+ // summary: List containers
+ // description: Returns a list of containers
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: string
+ // description: |
+ // Returns a list of containers.
+ // - ancestor=(<image-name>[:<tag>], <image id>, or <image@digest>)
+ // - before=(<container id> or <container name>)
+ // - expose=(<port>[/<proto>]|<startport-endport>/[<proto>])
+ // - exited=<int> containers with exit code of <int>
+ // - health=(starting|healthy|unhealthy|none)
+ // - id=<ID> a container's ID
+ // - is-task=(true|false)
+ // - label=key or label="key=value" of a container label
+ // - name=<name> a container's name
+ // - network=(<network id> or <network name>)
+ // - publish=(<port>[/<proto>]|<startport-endport>/[<proto>])
+ // - since=(<container id> or <container name>)
+ // - status=(created|restarting|running|removing|paused|exited|dead)
+ // - volume=(<volume name> or <mount point destination>)
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // "$ref": "#/responses/DocsListContainer"
+ // '400':
+ // "$ref": "#/responses/BadParamError"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/json"), APIHandler(s.Context, generic.ListContainers)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/prune containers pruneContainers
+ // ---
+ // summary: Delete stopped containers
+ // description: Remove containers not in use
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: string
+ // description: |
+ // Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters:
+ // - `until=<timestamp>` Prune containers created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time.
+ // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune containers with (or without, in case `label!=...` is used) the specified labels.
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // "$ref": "#/responses/DocsContainerPruneReport"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/prune"), APIHandler(s.Context, generic.PruneContainers)).Methods(http.MethodPost)
+ // swagger:operation DELETE /containers/{nameOrID} containers removeContainer
+ // ---
+ // summary: Remove a container
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: force
+ // type: bool
+ // default: false
+ // description: If the container is running, kill it before removing it.
+ // - in: query
+ // name: v
+ // type: bool
+ // default: false
+ // description: Remove the volumes associated with the container.
+ // - in: query
+ // name: link
+ // type: bool
+ // description: not supported
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '400':
+ // "$ref": "#/responses/BadParamError"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '409':
+ // "$ref": "#/responses/ConflictError"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}"), APIHandler(s.Context, generic.RemoveContainer)).Methods(http.MethodDelete)
+ // swagger:operation GET /containers/{nameOrID}/json containers getContainer
+ // ---
+ // summary: Inspect container
+ // description: Return low-level information about a container.
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or id of the container
+ // - in: query
+ // name: size
+ // type: bool
+ // default: false
+ // description: include the size of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // "$ref": "#/responses/DocsContainerInspectResponse"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/json"), APIHandler(s.Context, generic.GetContainer)).Methods(http.MethodGet)
+ // swagger:operation post /containers/{nameOrID}/kill containers killcontainer
+ // ---
+ // summary: Kill container
+ // description: Signal to send to the container as an integer or string (e.g. SIGINT)
+ // 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
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '409':
+ // "$ref": "#/responses/ConflictError"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/kill"), APIHandler(s.Context, generic.KillContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{nameOrID}/logs containers LogsFromContainer
+ // ---
+ // summary: Get container logs
+ // description: Get stdout and stderr logs from a container.
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: follow
+ // type: bool
+ // description: Keep connection after returning logs.
+ // - in: query
+ // name: stdout
+ // type: bool
+ // description: not supported
+ // - in: query
+ // name: stderr
+ // type: bool
+ // description: not supported?
+ // - in: query
+ // name: since
+ // type: string
+ // description: Only return logs since this time, as a UNIX timestamp
+ // - in: query
+ // name: until
+ // type: string
+ // description: Only return logs before this time, as a UNIX timestamp
+ // - in: query
+ // name: timestamps
+ // type: bool
+ // default: false
+ // description: Add timestamps to every log line
+ // - in: query
+ // name: tail
+ // type: string
+ // description: Only return this number of log lines from the end of the logs
+ // default: all
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: logs returned as a stream in response body.
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/logs"), APIHandler(s.Context, generic.LogsFromContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{nameOrID}/pause containers pauseContainer
+ // ---
+ // summary: Pause container
+ // description: Use the cgroups freezer to suspend all processes in a container.
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ 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
+ // ---
+ // summary: 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
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/restart"), APIHandler(s.Context, handlers.RestartContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{nameOrID}/start containers startContainer
+ // ---
+ // summary: 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':
+ // "$ref": "#/responses/ContainerAlreadyStartedError"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/start"), APIHandler(s.Context, handlers.StartContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{nameOrID}/stats containers statsContainer
+ // ---
+ // summary: Get stats for a container
+ // description: This returns a live stream of a container’s resource usage statistics.
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // - in: query
+ // name: stream
+ // type: bool
+ // default: true
+ // description: Stream the output
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: no error
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/stats"), APIHandler(s.Context, generic.StatsContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{nameOrID}/stop containers stopContainer
+ // ---
+ // summary: 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':
+ // "$ref": "#/responses/ContainerAlreadyStoppedError"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/stop"), APIHandler(s.Context, handlers.StopContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{nameOrID}/top containers topContainer
+ // ---
+ // summary: 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':
+ // "ref": "#/responses/DockerTopResponse"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{nameOrID}/unpause containers unpauseContainer
+ // ---
+ // summary: Unpause container
+ // description: Resume a paused container
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name:..*}/unpause"), APIHandler(s.Context, handlers.UnpauseContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{nameOrID}/wait containers waitContainer
+ // ---
+ // summary: Wait on a container to exit
+ // description: Block until a container stops, then returns the exit code.
+ // 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:
+ // '200':
+ // $ref: "#/responses/ContainerWaitResponse"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ 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 libpodListContainers
+ // ---
+ // summary: List containers
+ // description: Returns a list of containers
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // type: array
+ // items:
+ // "$ref": "#/responses/LibpodListContainersResponse"
+ // '400':
+ // "$ref": "#/responses/BadParamError"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/json"), APIHandler(s.Context, libpod.ListContainers)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/prune containers libpodPruneContainers
+ // ---
+ // summary: Prune unused containers
+ // description: Remove stopped and exited containers
+ // parameters:
+ // - in: query
+ // name: force
+ // type: bool
+ // description: something
+ // - in: query
+ // name: filters
+ // type: string
+ // description: |
+ // Filters to process on the prune list, encoded as JSON (a `map[string][]string`). Available filters:
+ // - `until=<timestamp>` Prune containers created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time.
+ // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune containers with (or without, in case `label!=...` is used) the specified labels.
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: to be determined
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/prune"), APIHandler(s.Context, libpod.PruneContainers)).Methods(http.MethodPost)
+ // swagger:operation GET /libpod/containers/showmounted containers showMounterContainers
+ // ---
+ // summary: Show mounted containers
+ // description: Lists all mounted containers mount points
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: mounted containers
+ // schema:
+ // type: object
+ // additionalProperties:
+ // type: string
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/showmounted"), APIHandler(s.Context, libpod.ShowMountedContainers)).Methods(http.MethodGet)
+ // swagger:operation DELETE /libpod/containers/json containers libpodRemoveContainer
+ // ---
+ // summary: 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: delete volumes
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '400':
+ // "$ref": "#/responses/BadParamError"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '409':
+ // "$ref": "#/responses/ConflictError"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}"), APIHandler(s.Context, libpod.RemoveContainer)).Methods(http.MethodDelete)
+ // swagger:operation GET /libpod/containers/{nameOrID}/json containers libpodGetContainer
+ // ---
+ // summary: Inspect container
+ // description: Return low-level information about a 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':
+ // "$ref": "#/responses/LibpodInspectContainerResponse"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/json"), APIHandler(s.Context, libpod.GetContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{nameOrID}/kill containers libpodKillContainer
+ // ---
+ // summary: Kill container
+ // description: send a signal to a container, defaults to killing the 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
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '409':
+ // "$ref": "#/responses/ConflictError"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/kill"), APIHandler(s.Context, libpod.KillContainer)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/containers/{nameOrID}/mount containers mountContainer
+ // ---
+ // summary: Mount a container
+ // description: Mount a container to the filesystem
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: mounted container
+ // schema:
+ // description: id
+ // type: string
+ // example: 3c784de79b791b4ebd3ac55e511f97fedc042328499554937a3f8bfd9c1a2cb8
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/mount"), APIHandler(s.Context, libpod.MountContainer)).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 libpodPauseContainer
+ // ---
+ // summary: Pause a container
+ // description: Use the cgroups freezer to suspend all processes in a container.
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/pause"), APIHandler(s.Context, handlers.PauseContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{nameOrID}/restart containers libpodRestartContainer
+ // ---
+ // summary: Restart a 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
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/restart"), APIHandler(s.Context, handlers.RestartContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{nameOrID}/start containers libpodStartContainer
+ // ---
+ // summary: 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':
+ // "$ref": "#/responses/ContainerAlreadyStartedError"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ 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 libpodUnpauseContainer
+ // ---
+ // summary: 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
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/unpause"), APIHandler(s.Context, handlers.UnpauseContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{nameOrID}/wait containers libpodWaitContainer
+ // ---
+ // summary: 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
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/wait"), APIHandler(s.Context, libpod.WaitContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{nameOrID}/exists containers containerExists
+ // ---
+ // summary: Check if container exists
+ // description: Quick way to determine if a container exists by name or ID
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: container exists
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/exists"), APIHandler(s.Context, libpod.ContainerExists)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{nameOrID}/stop containers libpodStopContainer
+ // ---
+ // summary: 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':
+ // "$ref": "#/responses/ContainerAlreadyStoppedError"
+ // '404':
+ // "$ref": "#/responses/NoSuchContainer"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ 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..56cf96de1
--- /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": "#/responses/InternalError"
+ 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..916534fc7
--- /dev/null
+++ b/pkg/api/server/register_images.go
@@ -0,0 +1,568 @@
+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 compat_images createImage
+ //
+ // ---
+ // summary: Create an image from an image
+ // description: Create an image by either pulling it from a registry or importing it.
+ // 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: "to be determined"
+ // '404':
+ // description: repo or image does not exist
+ // schema:
+ // $ref: "#/responses/InternalError"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // $ref: '#/responses/GenericError'
+ r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}")
+ // swagger:operation POST /images/create compat_images createImage
+ // ---
+ // summary: Create an image from Source
+ // description: Create an image by either pulling it from a registry or importing it.
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: query
+ // name: fromSrc
+ // type: string
+ // description: needs description
+ // - in: query
+ // name: changes
+ // type: to be determined
+ // description: needs description
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // $ref: "to be determined"
+ // '404':
+ // description: repo or image does not exist
+ // schema:
+ // $ref: "#/responses/InternalError"
+ // '500':
+ // description: unexpected error
+ // schema:
+ // $ref: '#/responses/GenericError'
+ r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromSrc)).Methods(http.MethodPost).Queries("fromSrc", "{fromSrc}")
+ // swagger:operation GET /images/json compat_images listImages
+ // ---
+ // summary: List Images
+ // description: Returns a list of images on the server. Note that it uses a different, smaller representation of an image than inspecting a single image.
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // type: array
+ // items:
+ // schema:
+ // $ref: "#/responses/DockerImageSummary"
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/json"), APIHandler(s.Context, generic.GetImages)).Methods(http.MethodGet)
+ // swagger:operation POST /images/load compat_images loadImage
+ //
+ // ---
+ // summary: Import image
+ // description: Load a set of images and tags into a repository.
+ // parameters:
+ // - in: query
+ // name: quiet
+ // type: bool
+ // description: not supported
+ // - in: body
+ // description: tarball of container image
+ // type: string
+ // format: binary
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: no error
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/load"), APIHandler(s.Context, handlers.LoadImage)).Methods(http.MethodPost)
+ // swagger:operation POST /images/prune compat_images pruneImages
+ // ---
+ // summary: Prune unused images
+ // description: Remove images from local storage that are not being used by a container
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: string
+ // description: |
+ // filters to apply to image pruning, encoded as JSON (map[string][]string). Available filters:
+ // - `dangling=<boolean>` When set to `true` (or `1`), prune only
+ // unused *and* untagged images. When set to `false`
+ // (or `0`), all unused images are pruned.
+ // - `until=<string>` Prune images created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time.
+ // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune images with (or without, in case `label!=...` is used) the specified labels.
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/prune"), APIHandler(s.Context, generic.PruneImages)).Methods(http.MethodPost)
+ // swagger:operation GET /images/search compat_images searchImages
+ // ---
+ // summary: Search images
+ // description: Search registries for an image
+ // 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: string
+ // description: |
+ // A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
+ // - `is-automated=(true|false)`
+ // - `is-official=(true|false)`
+ // - `stars=<number>` Matches images that has at least 'number' stars.
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // $ref: "#/responses/DocsSearchResponse"
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/search"), APIHandler(s.Context, handlers.SearchImages)).Methods(http.MethodGet)
+ // swagger:operation DELETE /images/{nameOrID} compat_images removeImage
+ // ---
+ // summary: Remove Image
+ // description: Delete an image from local storage
+ // 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. will be logged as an invalid parameter if enabled
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // '400':
+ // $ref: '#/responses/BadParamError'
+ // '409':
+ // $ref: '#/responses/ConflictError'
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/{name:..*}"), APIHandler(s.Context, handlers.RemoveImage)).Methods(http.MethodDelete)
+ // swagger:operation GET /images/{nameOrID}/get compat_images exportImage
+ // ---
+ // summary: Export an image
+ // description: Export an image in tarball format
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: no error
+ // schema:
+ // type: string
+ // format: binary
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/{name:..*}/get"), APIHandler(s.Context, generic.ExportImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/{nameOrID}/history compat_images imageHistory
+ // ---
+ // summary: History of an image
+ // description: Return parent layers of an image.
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // $ref: "#/responses/DocsHistory"
+ // '404':
+ // $ref: "#/responses/NoSuchImage"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/images/{name:..*}/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/{nameOrID}/json compat_images inspectImage
+ // ---
+ // summary: Inspect an image
+ // description: Return low-level information about an image.
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // $ref: "#/responses/DocsImageInspect"
+ // '404':
+ // $ref: "#/responses/NoSuchImage"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/images/{name:..*}/json"), APIHandler(s.Context, generic.GetImage))
+ // swagger:operation POST /images/{nameOrID}/tag compat_images tagImage
+ // ---
+ // summary: Tag an image
+ // description: Tag an image so that it becomes part of a repository.
+ // 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:
+ // $ref: '#/responses/BadParamError'
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 409:
+ // $ref: '#/responses/ConflictError'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/{name:..*}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
+ // swagger:operation POST /commit/ compat_commit commitContainer
+ // ---
+ // summary: 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':
+ // $ref: '#/responses/NoSuchImage'
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/commit"), APIHandler(s.Context, generic.CommitContainer)).Methods(http.MethodPost)
+
+ /*
+ libpod endpoints
+ */
+
+ // swagger:operation POST /libpod/images/{nameOrID}/exists images libpodImageExists
+ // ---
+ // summary: Image exists
+ // description: 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
+ // responses:
+ // '204':
+ // description: image exists
+ // '404':
+ // $ref: '#/responses/NoSuchImage'
+ // '500':
+ // $ref: '#/responses/InternalError'
+ 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 libpodImageHistory
+ // ---
+ // summary: History of an image
+ // description: Return parent layers 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: "#/responses/HistoryResponse"
+ // '404':
+ // $ref: '#/responses/NoSuchImage'
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/images/json images libpodListImages
+ // ---
+ // summary: List Images
+ // description: Returns a list of images on the server
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // $ref: "#/responses/DockerImageSummary"
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/json"), APIHandler(s.Context, libpod.GetImages)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/images/load images libpodLoadImage
+ // ---
+ // summary: Import image
+ // description: Load a set of images and tags into a repository.
+ // parameters:
+ // - in: query
+ // name: quiet
+ // type: bool
+ // description: not supported
+ // - in: body
+ // description: tarball of container image
+ // type: string
+ // format: binary
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: no error
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/load"), APIHandler(s.Context, handlers.LoadImage)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/images/prune images libpodPruneImages
+ // ---
+ // summary: Prune unused images
+ // description: Remove images that are not being used by a container
+ // parameters:
+ // - in: query
+ // name: filters
+ // type: string
+ // description: |
+ // filters to apply to image pruning, encoded as JSON (map[string][]string). Available filters:
+ // - `dangling=<boolean>` When set to `true` (or `1`), prune only
+ // unused *and* untagged images. When set to `false`
+ // (or `0`), all unused images are pruned.
+ // - `until=<string>` Prune images created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time.
+ // - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune images with (or without, in case `label!=...` is used) the specified labels.
+ // - in: query
+ // name: all
+ // type: bool
+ // description: prune all images
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // items:
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/prune"), APIHandler(s.Context, libpod.PruneImages)).Methods(http.MethodPost)
+ // swagger:operation GET /libpod/images/search images libpodSearchImages
+ // ---
+ // summary: Search images
+ // description: Search registries for 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: string
+ // description: |
+ // A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
+ // - `is-automated=(true|false)`
+ // - `is-official=(true|false)`
+ // - `stars=<number>` Matches images that has at least 'number' stars.
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // $ref: "#/responses/DocsSearchResponse"
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/search"), APIHandler(s.Context, handlers.SearchImages)).Methods(http.MethodGet)
+ // swagger:operation DELETE /libpod/images/{nameOrID} images libpodRemoveImage
+ // ---
+ // summary: Remove Image
+ // description: Delete an image from local store
+ // parameters:
+ // - in: query
+ // name: force
+ // type: bool
+ // description: remove the image even if used by containers or has other tags
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // schema:
+ // items:
+ // $ref: "#/responses/DocsIageDeleteResponse"
+ // '400':
+ // $ref: "#/responses/BadParamError"
+ // '404':
+ // $ref: '#/responses/NoSuchImage'
+ // '409':
+ // $ref: '#/responses/ConflictError'
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name:..*}"), APIHandler(s.Context, handlers.RemoveImage)).Methods(http.MethodDelete)
+ // swagger:operation GET /libpod/images/{nameOrID}/get images libpoodExportImage
+ // ---
+ // summary: Export an image
+ // description: Export an image as a tarball
+ // 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':
+ // description: no error
+ // schema:
+ // type: string
+ // format: binary
+ // '404':
+ // $ref: '#/responses/NoSuchImage'
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name:..*}/get"), APIHandler(s.Context, libpod.ExportImage)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/images/{nameOrID}/json images libpodInspectImage
+ // ---
+ // summary: Inspect an image
+ // description: Obtain low-level information about an image
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the container
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // $ref: "#/responses/DocsLibpodInspectImageResponse"
+ // '404':
+ // $ref: '#/responses/NoSuchImage'
+ // '500':
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name:..*}/json"), APIHandler(s.Context, libpod.GetImage))
+ // swagger:operation POST /libpod/images/{nameOrID}/tag images libpodTagImage
+ // ---
+ // summary: Tag an image
+ // description: Tag an image so that it becomes part of a repository.
+ // 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':
+ // $ref: '#/responses/BadParamError'
+ // '404':
+ // $ref: '#/responses/NoSuchImage'
+ // '409':
+ // $ref: '#/responses/ConflictError'
+ // '500':
+ // $ref: '#/responses/InternalError'
+ 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..a7fb18721
--- /dev/null
+++ b/pkg/api/server/register_info.go
@@ -0,0 +1,24 @@
+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 libpodGetInfo
+ // ---
+ // summary: Get info
+ // description: Returns information on the system and libpod configuration
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: to be determined
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ 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..5069326b6
--- /dev/null
+++ b/pkg/api/server/register_pods.go
@@ -0,0 +1,239 @@
+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 {
+ // swagger:operation GET /libpod/pods/json pods ListPods
+ // ---
+ // summary: List pods
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: query
+ // name: filters
+ // descriptions: needs description and plumbing for filters
+ // responses:
+ // '200':
+ // properties:
+ // items:
+ // $ref: "#/responses/ListPodsResponse"
+ // type: array
+ // '400':
+ // $ref: "#/responses/BadParamError"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ 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)
+ // swagger:operation POST /libpod/pods/prune pods PrunePods
+ // ---
+ // summary: Prune unused pods
+ // parameters:
+ // - in: query
+ // name: force
+ // description: force delete
+ // type: bool
+ // default: false
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '400':
+ // $ref: "#/responses/BadParamError"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/prune"), APIHandler(s.Context, libpod.PodPrune)).Methods(http.MethodPost)
+ // swagger:operation DELETE /libpod/pods/{nameOrID} pods removePod
+ // ---
+ // summary: Remove pod
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // - in: query
+ // name: force
+ // type: bool
+ // description: force delete
+ // responses:
+ // '204':
+ // description: no error
+ // '400':
+ // $ref: "#/responses/BadParamError"
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}"), APIHandler(s.Context, libpod.PodDelete)).Methods(http.MethodDelete)
+ // swagger:operation GET /libpod/pods/{nameOrID}/json pods inspectPod
+ // ---
+ // summary: Inspect pod
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // responses:
+ // '200':
+ // $ref: "#/responses/InspectPodResponse"
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/json"), APIHandler(s.Context, libpod.PodInspect)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/pods/{nameOrID}/exists pods podExists
+ // ---
+ // summary: Pod exists
+ // description: Check if a pod exists by name or ID
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // responses:
+ // '204':
+ // description: pod exists
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/exists"), APIHandler(s.Context, libpod.PodExists)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/pods/{nameOrID}/kill pods killPod
+ // ---
+ // summary: Kill a pod
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // - in: query
+ // name: signal
+ // type: int
+ // description: signal to be sent to pod
+ // responses:
+ // '204':
+ // description: no error
+ // '400':
+ // $ref: "#/responses/BadParamError"
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '409':
+ // $ref: "#/responses/ConflictError"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/kill"), APIHandler(s.Context, libpod.PodKill)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{nameOrID}/pause pods pausePod
+ // ---
+ // summary: Pause a pod
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // responses:
+ // '204':
+ // description: no error
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/pause"), APIHandler(s.Context, libpod.PodPause)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{nameOrID}/restart pods restartPod
+ // ---
+ // summary: Restart a pod
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // responses:
+ // '204':
+ // description: no error
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/restart"), APIHandler(s.Context, libpod.PodRestart)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{nameOrID}/start pods startPod
+ // ---
+ // summary: Start a pod
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // responses:
+ // '204':
+ // description: no error
+ // '304':
+ // $ref: "#/responses/PodAlreadyStartedError"
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/start"), APIHandler(s.Context, libpod.PodStart)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{nameOrID}/stop pods stopPod
+ // ---
+ // summary: Stop a pod
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // - in: query
+ // name: t
+ // type: int
+ // description: timeout
+ // responses:
+ // '204':
+ // description: no error
+ // '304':
+ // $ref: "#/responses/PodAlreadyStoppedError"
+ // '400':
+ // $ref: "#/responses/BadParamError"
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name:..*}/stop"), APIHandler(s.Context, libpod.PodStop)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{nameOrID}/unpause pods unpausePod
+ // ---
+ // summary: Unpause a pod
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the pod
+ // responses:
+ // '204':
+ // description: no error
+ // '404':
+ // $ref: "#/responses/NoSuchPod"
+ // '500':
+ // $ref: "#/responses/InternalError"
+ 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..63d8acfde
--- /dev/null
+++ b/pkg/api/server/register_swarm.go
@@ -0,0 +1,27 @@
+package server
+
+import (
+ "errors"
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers/utils"
+ "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..34138cfbf
--- /dev/null
+++ b/pkg/api/server/register_volumes.go
@@ -0,0 +1,77 @@
+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 {
+ // swagger:operation POST /libpod/volumes/create volumes createVolume
+ // ---
+ // summary: Create a volume
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // description: tbd
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ 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)
+ // swagger:operation POST /volumes/prune volumes pruneVolumes
+ // ---
+ // summary: Prune volumes
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.Handle("/libpod/volumes/prune", APIHandler(s.Context, libpod.PruneVolumes)).Methods(http.MethodPost)
+ // swagger:operation GET /volumes/{nameOrID}/json volumes inspectVolume
+ // ---
+ // summary: Inspect volume
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the volume
+ // produces:
+ // - application/json
+ // responses:
+ // '200':
+ // "$ref": "#/responses/InspectVolumeResponse"
+ // '404':
+ // "$ref": "#/responses/NoSuchVolume"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ r.Handle("/libpod/volumes/{name:..*}/json", APIHandler(s.Context, libpod.InspectVolume)).Methods(http.MethodGet)
+ // swagger:operation DELETE /volumes/{nameOrID} volumes removeVolume
+ // ---
+ // summary: Remove volume
+ // parameters:
+ // - in: path
+ // name: nameOrID
+ // required: true
+ // description: the name or ID of the volume
+ // - in: query
+ // name: force
+ // type: bool
+ // description: force removal
+ // produces:
+ // - application/json
+ // responses:
+ // '204':
+ // description: no error
+ // '400':
+ // "$ref": "#/responses/BadParamError"
+ // '404':
+ // "$ref": "#/responses/NoSuchVolume"
+ // '500':
+ // "$ref": "#/responses/InternalError"
+ 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()
+}
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
new file mode 100644
index 000000000..95129e637
--- /dev/null
+++ b/pkg/api/server/swagger.go
@@ -0,0 +1,138 @@
+package server
+
+import (
+ "github.com/containers/libpod/pkg/api/handlers"
+ "github.com/containers/libpod/pkg/api/handlers/utils"
+)
+
+// No such image
+// swagger:response NoSuchImage
+type swagErrNoSuchImage struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// No such container
+// swagger:response NoSuchContainer
+type swagErrNoSuchContainer struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// No such volume
+// swagger:response NoSuchVolume
+type swagErrNoSuchVolume struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// No such pod
+// swagger:response NoSuchPod
+type swagErrNoSuchPod struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Internal error
+// swagger:response InternalError
+type swagInternalError struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Generic error
+// swagger:response GenericError
+type swagGenericError struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Conflict error
+// swagger:response ConflictError
+type swagConflictError struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Bad parameter
+// swagger:response BadParamError
+type swagBadParamError struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Container already started
+// swagger:response ContainerAlreadyStartedError
+type swagContainerAlreadyStartedError struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Container already stopped
+// swagger:response ContainerAlreadyStoppedError
+type swagContainerAlreadyStopped struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Pod already started
+// swagger:response PodAlreadyStartedError
+type swagPodAlreadyStartedError struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Pod already stopped
+// swagger:response PodAlreadyStoppedError
+type swagPodAlreadyStopped struct {
+ // in:body
+ Body struct {
+ utils.ErrorModel
+ }
+}
+
+// Image summary
+// swagger:response DockerImageSummary
+type swagImageSummary struct {
+ // in:body
+ Body struct {
+ handlers.ImageSummary
+ }
+}
+
+// List Containers
+// swagger:response DocsListContainer
+type swagListContainers struct {
+ // in:body
+ Body struct {
+ // This causes go-swagger to crash
+ //handlers.Container
+ }
+}
+
+// To be determined
+// swagger:response tbd
+type swagTBD struct {
+}