summaryrefslogtreecommitdiff
path: root/pkg/api
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api')
-rw-r--r--pkg/api/Makefile16
-rw-r--r--pkg/api/handlers/containers.go53
-rw-r--r--pkg/api/handlers/containers_create.go (renamed from pkg/api/handlers/generic/containers_create.go)13
-rw-r--r--pkg/api/handlers/decoder.go91
-rw-r--r--pkg/api/handlers/events.go25
-rw-r--r--pkg/api/handlers/generic/config.go9
-rw-r--r--pkg/api/handlers/generic/containers.go80
-rw-r--r--pkg/api/handlers/generic/images.go73
-rw-r--r--pkg/api/handlers/generic/swagger.go4
-rw-r--r--pkg/api/handlers/handler.go25
-rw-r--r--pkg/api/handlers/images.go58
-rw-r--r--pkg/api/handlers/images_build.go229
-rw-r--r--pkg/api/handlers/libpod/containers.go60
-rw-r--r--pkg/api/handlers/libpod/images.go78
-rw-r--r--pkg/api/handlers/libpod/pods.go70
-rw-r--r--pkg/api/handlers/swagger.go15
-rw-r--r--pkg/api/handlers/types.go14
-rw-r--r--pkg/api/handlers/utils/containers.go21
-rw-r--r--pkg/api/handlers/utils/errors.go27
-rw-r--r--pkg/api/handlers/utils/handler.go8
-rw-r--r--pkg/api/handlers/utils/images.go17
-rw-r--r--pkg/api/server/docs.go30
-rw-r--r--pkg/api/server/listener_api.go31
-rw-r--r--pkg/api/server/register_containers.go849
-rw-r--r--pkg/api/server/register_distribution.go2
-rw-r--r--pkg/api/server/register_events.go13
-rw-r--r--pkg/api/server/register_healthcheck.go2
-rw-r--r--pkg/api/server/register_images.go648
-rw-r--r--pkg/api/server/register_info.go8
-rw-r--r--pkg/api/server/register_pods.go241
-rw-r--r--pkg/api/server/register_volumes.go32
-rw-r--r--pkg/api/server/server.go86
-rw-r--r--pkg/api/server/swagger.go26
33 files changed, 1792 insertions, 1162 deletions
diff --git a/pkg/api/Makefile b/pkg/api/Makefile
index 5fb4e7da5..f564b6516 100644
--- a/pkg/api/Makefile
+++ b/pkg/api/Makefile
@@ -1,3 +1,13 @@
-swagger:
- swagger generate spec -o swagger.yaml -w ./
- cat tags.yaml >> swagger.yaml
+export GO111MODULE=off
+
+SWAGGER_OUT ?= swagger.yaml
+
+validate: ${SWAGGER_OUT}
+ swagger validate ${SWAGGER_OUT}
+
+.PHONY: ${SWAGGER_OUT}
+${SWAGGER_OUT}:
+ # generate doesn't remove file on error
+ rm -f ${SWAGGER_OUT}
+ swagger generate spec -o ${SWAGGER_OUT} -i tags.yaml -w ./
+
diff --git a/pkg/api/handlers/containers.go b/pkg/api/handlers/containers.go
index 6b09321a0..b5c78ce53 100644
--- a/pkg/api/handlers/containers.go
+++ b/pkg/api/handlers/containers.go
@@ -2,6 +2,7 @@ package handlers
import (
"fmt"
+ "github.com/docker/docker/api/types"
"net/http"
"github.com/containers/libpod/libpod"
@@ -192,3 +193,55 @@ func RestartContainer(w http.ResponseWriter, r *http.Request) {
// Success
utils.WriteResponse(w, http.StatusNoContent, "")
}
+
+func PruneContainers(w http.ResponseWriter, r *http.Request) {
+ var (
+ delContainers []string
+ space int64
+ )
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+
+ query := struct {
+ Filters map[string][]string `schema:"filter"`
+ }{}
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ filterFuncs, err := utils.GenerateFilterFuncsFromMap(runtime, query.Filters)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+
+ // Libpod response differs
+ if utils.IsLibpodRequest(r) {
+ var response []LibpodContainersPruneReport
+ for ctrID, size := range prunedContainers {
+ response = append(response, LibpodContainersPruneReport{ID: ctrID, SpaceReclaimed: size})
+ }
+ for ctrID, err := range pruneErrors {
+ response = append(response, LibpodContainersPruneReport{ID: ctrID, PruneError: err.Error()})
+ }
+ utils.WriteResponse(w, http.StatusOK, response)
+ return
+ }
+ for ctrID, size := range prunedContainers {
+ if pruneErrors[ctrID] == nil {
+ space += size
+ delContainers = append(delContainers, ctrID)
+ }
+ }
+ report := types.ContainersPruneReport{
+ ContainersDeleted: delContainers,
+ SpaceReclaimed: uint64(space),
+ }
+ utils.WriteResponse(w, http.StatusOK, report)
+}
diff --git a/pkg/api/handlers/generic/containers_create.go b/pkg/api/handlers/containers_create.go
index f98872690..4781b23bc 100644
--- a/pkg/api/handlers/generic/containers_create.go
+++ b/pkg/api/handlers/containers_create.go
@@ -1,4 +1,4 @@
-package generic
+package handlers
import (
"encoding/json"
@@ -10,7 +10,6 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
image2 "github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/namespaces"
createconfig "github.com/containers/libpod/pkg/spec"
@@ -25,7 +24,7 @@ import (
func CreateContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
- input := handlers.CreateContainerConfig{}
+ input := CreateContainerConfig{}
query := struct {
Name string `schema:"name"`
}{
@@ -40,7 +39,9 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
-
+ if len(input.HostConfig.Links) > 0 {
+ utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter"))
+ }
newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "NewFromLocal()"))
@@ -72,13 +73,13 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
}
response := ContainerCreateResponse{
- Id: ctr.ID(),
+ ID: ctr.ID(),
Warnings: []string{}}
utils.WriteResponse(w, http.StatusCreated, response)
}
-func makeCreateConfig(input handlers.CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) {
+func makeCreateConfig(input CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) {
var (
err error
init bool
diff --git a/pkg/api/handlers/decoder.go b/pkg/api/handlers/decoder.go
new file mode 100644
index 000000000..890d77ecc
--- /dev/null
+++ b/pkg/api/handlers/decoder.go
@@ -0,0 +1,91 @@
+package handlers
+
+import (
+ "encoding/json"
+ "reflect"
+ "time"
+
+ "github.com/gorilla/schema"
+ "github.com/sirupsen/logrus"
+)
+
+// NewAPIDecoder returns a configured schema.Decoder
+func NewAPIDecoder() *schema.Decoder {
+ _ = ParseDateTime
+
+ d := schema.NewDecoder()
+ d.IgnoreUnknownKeys(true)
+ d.RegisterConverter(map[string][]string{}, convertUrlValuesString)
+ d.RegisterConverter(time.Time{}, convertTimeString)
+ return d
+}
+
+// On client:
+// v := map[string][]string{
+// "dangling": {"true"},
+// }
+//
+// payload, err := jsoniter.MarshalToString(v)
+// if err != nil {
+// panic(err)
+// }
+// payload = url.QueryEscape(payload)
+func convertUrlValuesString(query string) reflect.Value {
+ f := map[string][]string{}
+
+ err := json.Unmarshal([]byte(query), &f)
+ if err != nil {
+ logrus.Infof("convertUrlValuesString: Failed to Unmarshal %s: %s", query, err.Error())
+ }
+
+ return reflect.ValueOf(f)
+}
+
+// isZero() can be used to determine if parsing failed.
+func convertTimeString(query string) reflect.Value {
+ var (
+ err error
+ t time.Time
+ )
+
+ for _, f := range []string{
+ time.UnixDate,
+ time.ANSIC,
+ time.RFC1123,
+ time.RFC1123Z,
+ time.RFC3339,
+ time.RFC3339Nano,
+ time.RFC822,
+ time.RFC822Z,
+ time.RFC850,
+ time.RubyDate,
+ time.Stamp,
+ time.StampMicro,
+ time.StampMilli,
+ time.StampNano,
+ } {
+ t, err = time.Parse(f, query)
+ if err == nil {
+ return reflect.ValueOf(t)
+ }
+
+ if _, isParseError := err.(*time.ParseError); isParseError {
+ // Try next format
+ continue
+ } else {
+ break
+ }
+ }
+
+ // We've exhausted all formats, or something bad happened
+ if err != nil {
+ logrus.Infof("convertTimeString: Failed to parse %s: %s", query, err.Error())
+ }
+ return reflect.ValueOf(time.Time{})
+}
+
+// ParseDateTime is a helper function to aid in parsing different Time/Date formats
+// isZero() can be used to determine if parsing failed.
+func ParseDateTime(query string) time.Time {
+ return convertTimeString(query).Interface().(time.Time)
+}
diff --git a/pkg/api/handlers/events.go b/pkg/api/handlers/events.go
index 900efa3da..44bf35254 100644
--- a/pkg/api/handlers/events.go
+++ b/pkg/api/handlers/events.go
@@ -1,9 +1,10 @@
package handlers
import (
- "encoding/json"
"fmt"
"net/http"
+ "strings"
+ "time"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/pkg/errors"
@@ -11,30 +12,24 @@ import (
func GetEvents(w http.ResponseWriter, r *http.Request) {
query := struct {
- Since string `json:"since"`
- Until string `json:"until"`
- Filters string `json:"filters"`
+ Since time.Time `schema:"since"`
+ Until time.Time `schema:"until"`
+ Filters map[string][]string `schema:"filters"`
}{}
if err := decodeQuery(r, &query); err != nil {
utils.Error(w, "Failed to parse parameters", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
}
- var filters = map[string][]string{}
- if found := hasVar(r, "filters"); found {
- if err := json.Unmarshal([]byte(query.Filters), &filters); err != nil {
- utils.BadRequest(w, "filters", query.Filters, err)
- return
+ var libpodFilters = []string{}
+ if _, found := r.URL.Query()["filters"]; found {
+ for k, v := range query.Filters {
+ libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
}
}
- var libpodFilters = make([]string, len(filters))
- for k, v := range filters {
- libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
- }
-
libpodEvents, err := getRuntime(r).GetEvents(libpodFilters)
if err != nil {
- utils.BadRequest(w, "filters", query.Filters, err)
+ utils.BadRequest(w, "filters", strings.Join(r.URL.Query()["filters"], ", "), err)
return
}
diff --git a/pkg/api/handlers/generic/config.go b/pkg/api/handlers/generic/config.go
deleted file mode 100644
index f715d25eb..000000000
--- a/pkg/api/handlers/generic/config.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package generic
-
-// ContainerCreateResponse is the response struct for creating a container
-type ContainerCreateResponse struct {
- // ID of the container created
- Id string `json:"Id"`
- // Warnings during container creation
- Warnings []string `json:"Warnings"`
-}
diff --git a/pkg/api/handlers/generic/containers.go b/pkg/api/handlers/generic/containers.go
index 5a0a51fd7..8dc73ae14 100644
--- a/pkg/api/handlers/generic/containers.go
+++ b/pkg/api/handlers/generic/containers.go
@@ -1,7 +1,6 @@
package generic
import (
- "context"
"encoding/binary"
"fmt"
"net/http"
@@ -11,12 +10,10 @@ import (
"time"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/logs"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/util"
- "github.com/docker/docker/api/types"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -47,14 +44,40 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
}
func ListContainers(w http.ResponseWriter, r *http.Request) {
+ var (
+ containers []*libpod.Container
+ err error
+ )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
-
- containers, err := runtime.GetAllContainers()
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ All bool `schema:"all"`
+ Limit int `schema:"limit"`
+ Size bool `schema:"size"`
+ Filters map[string][]string `schema:"filters"`
+ }{
+ // override any golang type defaults
+ }
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+ if query.All {
+ containers, err = runtime.GetAllContainers()
+ } else {
+ containers, err = runtime.GetRunningContainers()
+ }
if err != nil {
utils.InternalServerError(w, err)
return
}
-
+ if _, found := mux.Vars(r)["limit"]; found {
+ last := query.Limit
+ if len(containers) > last {
+ containers = containers[len(containers)-last:]
+ }
+ }
+ // TODO filters still need to be applied
infoData, err := runtime.Info()
if err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain system info"))
@@ -125,51 +148,6 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) {
})
}
-func PruneContainers(w http.ResponseWriter, r *http.Request) {
- runtime := r.Context().Value("runtime").(*libpod.Runtime)
-
- containers, err := runtime.GetAllContainers()
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
-
- deletedContainers := []string{}
- var spaceReclaimed uint64
- for _, ctnr := range containers {
- // Only remove stopped or exit'ed containers.
- state, err := ctnr.State()
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- switch state {
- case define.ContainerStateStopped, define.ContainerStateExited:
- default:
- continue
- }
-
- deletedContainers = append(deletedContainers, ctnr.ID())
- cSize, err := ctnr.RootFsSize()
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- spaceReclaimed += uint64(cSize)
-
- err = runtime.RemoveContainer(context.Background(), ctnr, false, false)
- if err != nil && !(errors.Cause(err) == define.ErrCtrRemoved) {
- utils.InternalServerError(w, err)
- return
- }
- }
- report := types.ContainersPruneReport{
- ContainersDeleted: deletedContainers,
- SpaceReclaimed: spaceReclaimed,
- }
- utils.WriteResponse(w, http.StatusOK, report)
-}
-
func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
diff --git a/pkg/api/handlers/generic/images.go b/pkg/api/handlers/generic/images.go
index 395f64064..ba1cf47b4 100644
--- a/pkg/api/handlers/generic/images.go
+++ b/pkg/api/handlers/generic/images.go
@@ -6,7 +6,6 @@ import (
"io/ioutil"
"net/http"
"os"
- "strconv"
"strings"
"github.com/containers/buildah"
@@ -16,12 +15,10 @@ import (
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/util"
- "github.com/containers/storage"
"github.com/docker/docker/api/types"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
func ExportImage(w http.ResponseWriter, r *http.Request) {
@@ -59,17 +56,14 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
}
func PruneImages(w http.ResponseWriter, r *http.Request) {
- // 200 no error
- // 500 internal
var (
- dangling bool = true
- err error
+ filters []string
)
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
query := struct {
- filters map[string]string
+ Filters map[string][]string `schema:"filters"`
}{
// This is where you can override the golang default value for one of fields
}
@@ -79,61 +73,24 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
return
}
- // FIXME This is likely wrong due to it not being a map[string][]string
-
- // until ts is not supported on podman prune
- if len(query.filters["until"]) > 0 {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "until is not supported yet"))
- return
- }
- // labels are not supported on podman prune
- if len(query.filters["label"]) > 0 {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "labelis not supported yet"))
- return
- }
-
- if len(query.filters["dangling"]) > 0 {
- dangling, err = strconv.ParseBool(query.filters["dangling"])
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "processing dangling filter"))
- return
+ idr := []types.ImageDeleteResponseItem{}
+ for k, v := range query.Filters {
+ for _, val := range v {
+ filters = append(filters, fmt.Sprintf("%s=%s", k, val))
}
}
- idr := []types.ImageDeleteResponseItem{}
- //
- // This code needs to be migrated to libpod to work correctly. I could not
- // work my around the information docker needs with the existing prune in libpod.
- //
- pruneImages, err := runtime.ImageRuntime().GetPruneImages(!dangling, []image2.ImageFilter{})
+ pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), false, filters)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to get images to prune"))
+ utils.InternalServerError(w, err)
return
}
- for _, p := range pruneImages {
- repotags, err := p.RepoTags()
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to get repotags for image"))
- return
- }
- if err := p.Remove(r.Context(), true); err != nil {
- if errors.Cause(err) == storage.ErrImageUsedByContainer {
- logrus.Warnf("Failed to prune image %s as it is in use: %v", p.ID(), err)
- continue
- }
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to prune image"))
- return
- }
- // newimageevent is not export therefore we cannot record the event. this will be fixed
- // when the prune is fixed in libpod
- // defer p.newImageEvent(events.Prune)
- response := types.ImageDeleteResponseItem{
- Deleted: fmt.Sprintf("sha256:%s", p.ID()), // I ack this is not ideal
- }
- if len(repotags) > 0 {
- response.Untagged = repotags[0]
- }
- idr = append(idr, response)
+ for _, p := range pruneCids {
+ idr = append(idr, types.ImageDeleteResponseItem{
+ Deleted: p,
+ })
}
+
+ //FIXME/TODO to do this exacty correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
ipr := types.ImagesPruneReport{
ImagesDeleted: idr,
SpaceReclaimed: 1, // TODO we cannot supply this right now
@@ -343,8 +300,6 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
}
func GetImages(w http.ResponseWriter, r *http.Request) {
- // 200 ok
- // 500 internal
images, err := utils.GetImages(w, r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed get images"))
diff --git a/pkg/api/handlers/generic/swagger.go b/pkg/api/handlers/generic/swagger.go
index 27e1fc18d..bfe527c41 100644
--- a/pkg/api/handlers/generic/swagger.go
+++ b/pkg/api/handlers/generic/swagger.go
@@ -1,11 +1,13 @@
package generic
+import "github.com/containers/libpod/pkg/api/handlers"
+
// Create container
// swagger:response ContainerCreateResponse
type swagCtrCreateResponse struct {
// in:body
Body struct {
- ContainerCreateResponse
+ handlers.ContainerCreateResponse
}
}
diff --git a/pkg/api/handlers/handler.go b/pkg/api/handlers/handler.go
index 2efeb1379..d60a5b239 100644
--- a/pkg/api/handlers/handler.go
+++ b/pkg/api/handlers/handler.go
@@ -15,10 +15,11 @@ func getVar(r *http.Request, k string) string {
return mux.Vars(r)[k]
}
-func hasVar(r *http.Request, k string) bool {
- _, found := mux.Vars(r)[k]
- return found
-}
+// func hasVar(r *http.Request, k string) bool {
+// _, found := mux.Vars(r)[k]
+// return found
+// }
+
func getName(r *http.Request) string {
return getVar(r, "name")
}
@@ -36,11 +37,11 @@ func getRuntime(r *http.Request) *libpod.Runtime {
return r.Context().Value("runtime").(*libpod.Runtime)
}
-func getHeader(r *http.Request, k string) string {
- return r.Header.Get(k)
-}
-
-func hasHeader(r *http.Request, k string) bool {
- _, found := r.Header[k]
- return found
-}
+// func getHeader(r *http.Request, k string) string {
+// return r.Header.Get(k)
+// }
+//
+// func hasHeader(r *http.Request, k string) bool {
+// _, found := r.Header[k]
+// return found
+// }
diff --git a/pkg/api/handlers/images.go b/pkg/api/handlers/images.go
index d4cddbfb2..3f66a63c8 100644
--- a/pkg/api/handlers/images.go
+++ b/pkg/api/handlers/images.go
@@ -3,7 +3,6 @@ package handlers
import (
"fmt"
"io"
- "io/ioutil"
"net/http"
"os"
"strconv"
@@ -74,8 +73,25 @@ func TagImage(w http.ResponseWriter, r *http.Request) {
}
func RemoveImage(w http.ResponseWriter, r *http.Request) {
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ query := struct {
+ noPrune bool
+ }{
+ // This is where you can override the golang default value for one of fields
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+ muxVars := mux.Vars(r)
+ if _, found := muxVars["noprune"]; found {
+ if query.noPrune {
+ utils.UnSupportedParameter("noprune")
+ }
+ }
name := mux.Vars(r)["name"]
newImage, err := runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
@@ -110,46 +126,6 @@ func GetImage(r *http.Request, name string) (*image.Image, error) {
return runtime.ImageRuntime().NewFromLocal(name)
}
-func LoadImage(w http.ResponseWriter, r *http.Request) {
- decoder := r.Context().Value("decoder").(*schema.Decoder)
- runtime := r.Context().Value("runtime").(*libpod.Runtime)
-
- query := struct {
- //quiet bool # quiet is currently unused
- }{
- // This is where you can override the golang default value for one of fields
- }
-
- if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
- return
- }
-
- var (
- err error
- writer io.Writer
- )
- f, err := ioutil.TempFile("", "api_load.tar")
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile"))
- return
- }
- if err := SaveFromBody(f, r); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file"))
- return
- }
- id, err := runtime.LoadImage(r.Context(), "", f.Name(), writer, "")
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to load image"))
- return
- }
- utils.WriteResponse(w, http.StatusOK, struct {
- Stream string `json:"stream"`
- }{
- Stream: fmt.Sprintf("Loaded image: %s\n", id),
- })
-}
-
func SaveFromBody(f *os.File, r *http.Request) error { // nolint
if _, err := io.Copy(f, r.Body); err != nil {
return err
diff --git a/pkg/api/handlers/images_build.go b/pkg/api/handlers/images_build.go
index c7c746392..b29c45574 100644
--- a/pkg/api/handlers/images_build.go
+++ b/pkg/api/handlers/images_build.go
@@ -1,6 +1,7 @@
package handlers
import (
+ "bytes"
"encoding/base64"
"encoding/json"
"fmt"
@@ -9,58 +10,66 @@ import (
"net/http"
"os"
"path/filepath"
+ "strconv"
"strings"
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/storage/pkg/archive"
- log "github.com/sirupsen/logrus"
+ "github.com/gorilla/mux"
)
func BuildImage(w http.ResponseWriter, r *http.Request) {
authConfigs := map[string]AuthConfig{}
- if hasHeader(r, "X-Registry-Config") {
- registryHeader := getHeader(r, "X-Registry-Config")
- authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(registryHeader))
+ if hdr, found := r.Header["X-Registry-Config"]; found && len(hdr) > 0 {
+ authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(hdr[0]))
if json.NewDecoder(authConfigsJSON).Decode(&authConfigs) != nil {
- utils.BadRequest(w, "X-Registry-Config", registryHeader, json.NewDecoder(authConfigsJSON).Decode(&authConfigs))
+ utils.BadRequest(w, "X-Registry-Config", hdr[0], json.NewDecoder(authConfigsJSON).Decode(&authConfigs))
return
}
}
+ if hdr, found := r.Header["Content-Type"]; found && len(hdr) > 0 {
+ if hdr[0] != "application/x-tar" {
+ utils.BadRequest(w, "Content-Type", hdr[0],
+ fmt.Errorf("Content-Type: %s is not supported. Should be \"application/x-tar\"", hdr[0]))
+ }
+ }
+
anchorDir, err := extractTarFile(r, w)
if err != nil {
utils.InternalServerError(w, err)
return
}
- // defer os.RemoveAll(anchorDir)
+ defer os.RemoveAll(anchorDir)
query := struct {
- Dockerfile string `json:"dockerfile"`
- Tag string `json:"t"`
- ExtraHosts string `json:"extrahosts"`
- Remote string `json:"remote"`
- Quiet bool `json:"q"`
- NoCache bool `json:"nocache"`
- CacheFrom string `json:"cachefrom"`
- Pull string `json:"pull"`
- Rm bool `json:"rm"`
- ForceRm bool `json:"forcerm"`
- Memory int `json:"memory"`
- MemSwap int `json:"memswap"`
- CpuShares int `json:"cpushares"`
- CpuSetCpus string `json:"cpusetcpus"`
- CpuPeriod int `json:"cpuperiod"`
- CpuQuota int `json:"cpuquota"`
- BuildArgs string `json:"buildargs"`
- ShmSize int `json:"shmsize"`
- Squash bool `json:"squash"`
- Labels string `json:"labels"`
- NetworkMode string `json:"networkmode"`
- Platform string `json:"platform"`
- Target string `json:"target"`
- Outputs string `json:"outputs"`
+ Dockerfile string `schema:"dockerfile"`
+ Tag string `schema:"t"`
+ ExtraHosts string `schema:"extrahosts"`
+ Remote string `schema:"remote"`
+ Quiet bool `schema:"q"`
+ NoCache bool `schema:"nocache"`
+ CacheFrom string `schema:"cachefrom"`
+ Pull bool `schema:"pull"`
+ Rm bool `schema:"rm"`
+ ForceRm bool `schema:"forcerm"`
+ Memory int64 `schema:"memory"`
+ MemSwap int64 `schema:"memswap"`
+ CpuShares uint64 `schema:"cpushares"`
+ CpuSetCpus string `schema:"cpusetcpus"`
+ CpuPeriod uint64 `schema:"cpuperiod"`
+ CpuQuota int64 `schema:"cpuquota"`
+ BuildArgs string `schema:"buildargs"`
+ ShmSize int `schema:"shmsize"`
+ Squash bool `schema:"squash"`
+ Labels string `schema:"labels"`
+ NetworkMode string `schema:"networkmode"`
+ Platform string `schema:"platform"`
+ Target string `schema:"target"`
+ Outputs string `schema:"outputs"`
+ Registry string `schema:"registry"`
}{
Dockerfile: "Dockerfile",
Tag: "",
@@ -69,7 +78,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
Quiet: false,
NoCache: false,
CacheFrom: "",
- Pull: "",
+ Pull: false,
Rm: true,
ForceRm: false,
Memory: 0,
@@ -86,6 +95,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
Platform: "",
Target: "",
Outputs: "",
+ Registry: "docker.io",
}
if err := decodeQuery(r, &query); err != nil {
@@ -93,80 +103,121 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
return
}
- // Tag is the name with optional tag...
- var name = query.Tag
- var tag string
+ var (
+ // Tag is the name with optional tag...
+ name = query.Tag
+ tag = "latest"
+ )
if strings.Contains(query.Tag, ":") {
tokens := strings.SplitN(query.Tag, ":", 2)
name = tokens[0]
tag = tokens[1]
}
+ if t, found := mux.Vars(r)["target"]; found {
+ name = t
+ }
+
var buildArgs = map[string]string{}
- if found := hasVar(r, "buildargs"); found {
- if err := json.Unmarshal([]byte(query.BuildArgs), &buildArgs); err != nil {
- utils.BadRequest(w, "buildargs", query.BuildArgs, err)
+ if a, found := mux.Vars(r)["buildargs"]; found {
+ if err := json.Unmarshal([]byte(a), &buildArgs); err != nil {
+ utils.BadRequest(w, "buildargs", a, err)
return
}
}
// convert label formats
var labels = []string{}
- if hasVar(r, "labels") {
+ if l, found := mux.Vars(r)["labels"]; found {
var m = map[string]string{}
- if err := json.Unmarshal([]byte(query.Labels), &m); err != nil {
- utils.BadRequest(w, "labels", query.Labels, err)
+ if err := json.Unmarshal([]byte(l), &m); err != nil {
+ utils.BadRequest(w, "labels", l, err)
return
}
for k, v := range m {
- labels = append(labels, fmt.Sprintf("%s=%v", k, v))
+ labels = append(labels, k+"="+v)
+ }
+ }
+
+ pullPolicy := buildah.PullIfMissing
+ if _, found := mux.Vars(r)["pull"]; found {
+ if query.Pull {
+ pullPolicy = buildah.PullAlways
}
}
+ // build events will be recorded here
+ var (
+ buildEvents = []string{}
+ progress = bytes.Buffer{}
+ )
+
buildOptions := imagebuildah.BuildOptions{
ContextDirectory: filepath.Join(anchorDir, "build"),
- PullPolicy: 0,
- Registry: "",
- IgnoreUnrecognizedInstructions: false,
+ PullPolicy: pullPolicy,
+ Registry: query.Registry,
+ IgnoreUnrecognizedInstructions: true,
Quiet: query.Quiet,
- Isolation: 0,
+ Isolation: buildah.IsolationChroot,
Runtime: "",
RuntimeArgs: nil,
TransientMounts: nil,
- Compression: 0,
+ Compression: archive.Gzip,
Args: buildArgs,
Output: name,
AdditionalTags: []string{tag},
- Log: nil,
- In: nil,
- Out: nil,
- Err: nil,
- SignaturePolicyPath: "",
- ReportWriter: nil,
- OutputFormat: "",
- SystemContext: nil,
- NamespaceOptions: nil,
- ConfigureNetwork: 0,
- CNIPluginPath: "",
- CNIConfigDir: "",
- IDMappingOptions: nil,
- AddCapabilities: nil,
- DropCapabilities: nil,
- CommonBuildOpts: &buildah.CommonBuildOptions{},
- DefaultMountsFilePath: "",
- IIDFile: "",
- Squash: query.Squash,
- Labels: labels,
- Annotations: nil,
- OnBuild: nil,
- Layers: false,
- NoCache: query.NoCache,
- RemoveIntermediateCtrs: query.Rm,
- ForceRmIntermediateCtrs: query.ForceRm,
- BlobDirectory: "",
- Target: query.Target,
- Devices: nil,
+ Log: func(format string, args ...interface{}) {
+ buildEvents = append(buildEvents, fmt.Sprintf(format, args...))
+ },
+ In: nil,
+ Out: &progress,
+ Err: &progress,
+ SignaturePolicyPath: "",
+ ReportWriter: &progress,
+ OutputFormat: buildah.Dockerv2ImageManifest,
+ SystemContext: nil,
+ NamespaceOptions: nil,
+ ConfigureNetwork: 0,
+ CNIPluginPath: "",
+ CNIConfigDir: "",
+ IDMappingOptions: nil,
+ AddCapabilities: nil,
+ DropCapabilities: nil,
+ CommonBuildOpts: &buildah.CommonBuildOptions{
+ AddHost: nil,
+ CgroupParent: "",
+ CPUPeriod: query.CpuPeriod,
+ CPUQuota: query.CpuQuota,
+ CPUShares: query.CpuShares,
+ CPUSetCPUs: query.CpuSetCpus,
+ CPUSetMems: "",
+ HTTPProxy: false,
+ Memory: query.Memory,
+ DNSSearch: nil,
+ DNSServers: nil,
+ DNSOptions: nil,
+ MemorySwap: query.MemSwap,
+ LabelOpts: nil,
+ SeccompProfilePath: "",
+ ApparmorProfile: "",
+ ShmSize: strconv.Itoa(query.ShmSize),
+ Ulimit: nil,
+ Volumes: nil,
+ },
+ DefaultMountsFilePath: "",
+ IIDFile: "",
+ Squash: query.Squash,
+ Labels: labels,
+ Annotations: nil,
+ OnBuild: nil,
+ Layers: false,
+ NoCache: query.NoCache,
+ RemoveIntermediateCtrs: query.Rm,
+ ForceRmIntermediateCtrs: query.ForceRm,
+ BlobDirectory: "",
+ Target: query.Target,
+ Devices: nil,
}
id, _, err := getRuntime(r).Build(r.Context(), buildOptions, query.Dockerfile)
@@ -179,17 +230,13 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
struct {
Stream string `json:"stream"`
}{
- Stream: fmt.Sprintf("Successfully built %s\n", id),
+ Stream: progress.String() + "\n" +
+ strings.Join(buildEvents, "\n") +
+ fmt.Sprintf("\nSuccessfully built %s\n", id),
})
}
func extractTarFile(r *http.Request, w http.ResponseWriter) (string, error) {
- var (
- // length int64
- // n int64
- copyErr error
- )
-
// build a home for the request body
anchorDir, err := ioutil.TempDir("", "libpod_builder")
if err != nil {
@@ -204,26 +251,14 @@ func extractTarFile(r *http.Request, w http.ResponseWriter) (string, error) {
}
defer tarBall.Close()
- // if hasHeader(r, "Content-Length") {
- // length, err := strconv.ParseInt(getHeader(r, "Content-Length"), 10, 64)
- // if err != nil {
- // return "", errors.New(fmt.Sprintf("Failed request: unable to parse Content-Length of '%s'", getHeader(r, "Content-Length")))
- // }
- // n, copyErr = io.CopyN(tarBall, r.Body, length+1)
- // } else {
- _, copyErr = io.Copy(tarBall, r.Body)
- // }
+ // Content-Length not used as too many existing API clients didn't honor it
+ _, err = io.Copy(tarBall, r.Body)
r.Body.Close()
- if copyErr != nil {
+ if err != nil {
utils.InternalServerError(w,
fmt.Errorf("failed Request: Unable to copy tar file from request body %s", r.RequestURI))
}
- log.Debugf("Content-Length: %s", getVar(r, "Content-Length"))
-
- // if hasHeader(r, "Content-Length") && n != length {
- // return "", errors.New(fmt.Sprintf("Failed request: Given Content-Length does not match file size %d != %d", n, length))
- // }
_, _ = tarBall.Seek(0, 0)
if err := archive.Untar(tarBall, buildDir, &archive.TarOptions{}); err != nil {
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 388be24b6..db1cf26ff 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -1,7 +1,9 @@
package libpod
import (
+ "fmt"
"net/http"
+ "strconv"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
@@ -17,8 +19,6 @@ func StopContainer(w http.ResponseWriter, r *http.Request) {
}
func ContainerExists(w http.ResponseWriter, r *http.Request) {
- // 404 no such container
- // 200 ok
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := mux.Vars(r)["name"]
_, err := runtime.LookupContainer(name)
@@ -46,12 +46,18 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
utils.RemoveContainer(w, r, query.Force, query.Vols)
}
func ListContainers(w http.ResponseWriter, r *http.Request) {
+ var (
+ filters []string
+ )
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- Filter []string `schema:"filter"`
- Last int `schema:"last"`
- Size bool `schema:"size"`
- Sync bool `schema:"sync"`
+ All bool `schema:"all"`
+ Filter map[string][]string `schema:"filter"`
+ Last int `schema:"last"`
+ Namespace bool `schema:"namespace"`
+ Pod bool `schema:"pod"`
+ Size bool `schema:"size"`
+ Sync bool `schema:"sync"`
}{
// override any golang type defaults
}
@@ -63,15 +69,22 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
}
runtime := r.Context().Value("runtime").(*libpod.Runtime)
opts := shared.PsOptions{
- All: true,
+ All: query.All,
Last: query.Last,
Size: query.Size,
Sort: "",
- Namespace: true,
+ Namespace: query.Namespace,
+ Pod: query.Pod,
Sync: query.Sync,
}
-
- pss, err := shared.GetPsContainerOutput(runtime, opts, query.Filter, 2)
+ if len(query.Filter) > 0 {
+ for k, v := range query.Filter {
+ for _, val := range v {
+ filters = append(filters, fmt.Sprintf("%s=%s", k, val))
+ }
+ }
+ }
+ pss, err := shared.GetPsContainerOutput(runtime, opts, filters, 2)
if err != nil {
utils.InternalServerError(w, err)
}
@@ -117,19 +130,12 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
}
func WaitContainer(w http.ResponseWriter, r *http.Request) {
- _, err := utils.WaitContainer(w, r)
+ exitCode, err := utils.WaitContainer(w, r)
if err != nil {
utils.InternalServerError(w, err)
return
}
- utils.WriteResponse(w, http.StatusNoContent, "")
-}
-
-func PruneContainers(w http.ResponseWriter, r *http.Request) {
- // TODO Needs rebase to get filers; Also would be handy to define
- // an actual libpod container prune method.
- // force
- // filters
+ utils.WriteResponse(w, http.StatusOK, strconv.Itoa(int(exitCode)))
}
func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
@@ -139,10 +145,22 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
// tail string
}
-func CreateContainer(w http.ResponseWriter, r *http.Request) {
+func UnmountContainer(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ name := mux.Vars(r)["name"]
+ conn, err := runtime.LookupContainer(name)
+ if err != nil {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+ // TODO In future it might be an improvement that libpod unmount return a
+ // "container not mounted" error so we can surface that to the endpoint user
+ if err := conn.Unmount(false); err != nil {
+ utils.InternalServerError(w, err)
+ }
+ utils.WriteResponse(w, http.StatusNoContent, "")
}
-
func MountContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := mux.Vars(r)["name"]
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 0d4e220a8..9f0876618 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -1,9 +1,12 @@
package libpod
import (
+ "fmt"
+ "io"
"io/ioutil"
"net/http"
"os"
+ "strconv"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/api/handlers"
@@ -42,12 +45,12 @@ func ImageExists(w http.ResponseWriter, r *http.Request) {
func ImageTree(w http.ResponseWriter, r *http.Request) {
// tree is a bit of a mess ... logic is in adapter and therefore not callable from here. needs rework
- //name := mux.Vars(r)["name"]
- //_, layerInfoMap, _, err := s.Runtime.Tree(name)
- //if err != nil {
+ // name := mux.Vars(r)["name"]
+ // _, layerInfoMap, _, err := s.Runtime.Tree(name)
+ // if err != nil {
// Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "Failed to find image information for %q", name))
// return
- //}
+ // }
// it is not clear to me how to deal with this given all the processing of the image
// is in main. we need to discuss how that really should be and return something useful.
handlers.UnsupportedHandler(w, r)
@@ -90,13 +93,14 @@ func GetImages(w http.ResponseWriter, r *http.Request) {
}
func PruneImages(w http.ResponseWriter, r *http.Request) {
- // 200 ok
- // 500 internal
+ var (
+ all bool
+ err error
+ )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- All bool `schema:"all"`
- Filters []string `schema:"filters"`
+ Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}
@@ -106,7 +110,19 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
- cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, query.Filters)
+
+ var libpodFilters = []string{}
+ if _, found := r.URL.Query()["filters"]; found {
+ all, err = strconv.ParseBool(query.Filters["all"][0])
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ for k, v := range query.Filters {
+ libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
+ }
+ }
+ cids, err := runtime.ImageRuntime().PruneImages(r.Context(), all, libpodFilters)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
@@ -163,3 +179,47 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
defer os.Remove(tmpfile.Name())
utils.WriteResponse(w, http.StatusOK, rdr)
}
+
+func ImportImage(w http.ResponseWriter, r *http.Request) {
+ // TODO this is basically wrong
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+
+ query := struct {
+ Changes map[string]string `json:"changes"`
+ Message string `json:"message"`
+ Quiet bool `json:"quiet"`
+ }{
+ // This is where you can override the golang default value for one of fields
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ var (
+ err error
+ writer io.Writer
+ )
+ f, err := ioutil.TempFile("", "api_load.tar")
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile"))
+ return
+ }
+ if err := handlers.SaveFromBody(f, r); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file"))
+ return
+ }
+ id, err := runtime.LoadImage(r.Context(), "", f.Name(), writer, "")
+ //id, err := runtime.Import(r.Context())
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to load image"))
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, struct {
+ Stream string `json:"stream"`
+ }{
+ Stream: fmt.Sprintf("Loaded image: %s\n", id),
+ })
+}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index daaf9d018..50d763338 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/util"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -107,7 +108,7 @@ func Pods(w http.ResponseWriter, r *http.Request) {
)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- filters []string `schema:"filters"`
+ Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}
@@ -116,10 +117,12 @@ func Pods(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
- if len(query.filters) > 0 {
+
+ if _, found := r.URL.Query()["filters"]; found {
utils.Error(w, "filters are not implemented yet", http.StatusInternalServerError, define.ErrNotImplemented)
return
}
+
pods, err := runtime.GetAllPods()
if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
@@ -163,7 +166,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
decoder = r.Context().Value("decoder").(*schema.Decoder)
)
query := struct {
- timeout int `schema:"t"`
+ Timeout int `schema:"t"`
}{
// override any golang type defaults
}
@@ -206,8 +209,8 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
return
}
- if query.timeout > 0 {
- _, stopError = pod.StopWithTimeout(r.Context(), false, query.timeout)
+ if query.Timeout > 0 {
+ _, stopError = pod.StopWithTimeout(r.Context(), false, query.Timeout)
} else {
_, stopError = pod.Stop(r.Context(), false)
}
@@ -265,7 +268,7 @@ func PodDelete(w http.ResponseWriter, r *http.Request) {
decoder = r.Context().Value("decoder").(*schema.Decoder)
)
query := struct {
- force bool `schema:"force"`
+ Force bool `schema:"force"`
}{
// override any golang type defaults
}
@@ -281,7 +284,7 @@ func PodDelete(w http.ResponseWriter, r *http.Request) {
utils.PodNotFound(w, name, err)
return
}
- if err := runtime.RemovePod(r.Context(), pod, true, query.force); err != nil {
+ if err := runtime.RemovePod(r.Context(), pod, true, query.Force); err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
@@ -306,43 +309,14 @@ func PodRestart(w http.ResponseWriter, r *http.Request) {
func PodPrune(w http.ResponseWriter, r *http.Request) {
var (
- err error
- pods []*libpod.Pod
runtime = r.Context().Value("runtime").(*libpod.Runtime)
- decoder = r.Context().Value("decoder").(*schema.Decoder)
)
- query := struct {
- force bool `schema:"force"`
- }{
- // override any golang type defaults
- }
-
- if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
- return
- }
-
- if query.force {
- pods, err = runtime.GetAllPods()
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
- } else {
- // TODO We need to make a libpod.PruneVolumes or this code will be a mess. Volumes
- // already does this right. It will also help clean this code path up with less
- // conditionals. We do this when we integrate with libpod again.
- utils.Error(w, "not implemented", http.StatusInternalServerError, errors.New("not implemented"))
+ pruned, err := runtime.PrunePods()
+ if err != nil {
+ utils.InternalServerError(w, err)
return
}
- for _, p := range pods {
- if err := runtime.RemovePod(r.Context(), p, true, query.force); err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
- }
- utils.WriteResponse(w, http.StatusNoContent, "")
+ utils.WriteResponse(w, http.StatusOK, pruned)
}
func PodPause(w http.ResponseWriter, r *http.Request) {
@@ -384,18 +358,27 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
var (
runtime = r.Context().Value("runtime").(*libpod.Runtime)
decoder = r.Context().Value("decoder").(*schema.Decoder)
+ signal = "SIGKILL"
)
query := struct {
- signal int `schema:"signal"`
+ signal string `schema:"signal"`
}{
// override any golang type defaults
}
-
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
+ muxVars := mux.Vars(r)
+ if _, found := muxVars["signal"]; found {
+ signal = query.signal
+ }
+
+ sig, err := util.ParseSignal(signal)
+ if err != nil {
+ utils.InternalServerError(w, errors.Wrapf(err, "unable to parse signal value"))
+ }
name := mux.Vars(r)["name"]
pod, err := runtime.LookupPod(name)
if err != nil {
@@ -419,8 +402,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
utils.Error(w, msg, http.StatusConflict, errors.Errorf("cannot kill a pod with no running containers: %s", pod.ID()))
return
}
- // TODO How do we differentiate if a signal was sent vs accepting the pod/container default?
- _, err = pod.Kill(uint(query.signal))
+ _, err = pod.Kill(uint(sig))
if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
diff --git a/pkg/api/handlers/swagger.go b/pkg/api/handlers/swagger.go
index c845c8195..faae98798 100644
--- a/pkg/api/handlers/swagger.go
+++ b/pkg/api/handlers/swagger.go
@@ -30,9 +30,7 @@ type swagImageInspect struct {
// swagger:response DocsImageDeleteResponse
type swagImageDeleteResponse struct {
// in:body
- Body struct {
- image.ImageDeleteResponse
- }
+ Body []image.ImageDeleteResponse
}
// Search results
@@ -60,6 +58,13 @@ type swagContainerPruneReport struct {
Body []ContainersPruneReport
}
+// Prune containers
+// swagger:response DocsLibpodPruneResponse
+type swagLibpodContainerPruneReport struct {
+ // in: body
+ Body []LibpodContainersPruneReport
+}
+
// Inspect container
// swagger:response DocsContainerInspectResponse
type swagContainerInspectResponse struct {
@@ -98,9 +103,7 @@ type swagLibpodInspectContainerResponse struct {
// swagger:response ListPodsResponse
type swagListPodsResponse struct {
// in:body
- Body struct {
- libpod.PodInspect
- }
+ Body []libpod.PodInspect
}
// Inspect pod
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 2526a3317..33cf1e95d 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -43,6 +43,12 @@ type ContainersPruneReport struct {
docker.ContainersPruneReport
}
+type LibpodContainersPruneReport struct {
+ ID string `json:"id"`
+ SpaceReclaimed int64 `json:"space"`
+ PruneError string `json:"error"`
+}
+
type Info struct {
docker.Info
BuildahVersion string
@@ -531,3 +537,11 @@ func portsToPortSet(input map[string]struct{}) (nat.PortSet, error) {
}
return ports, nil
}
+
+// ContainerCreateResponse is the response struct for creating a container
+type ContainerCreateResponse struct {
+ // ID of the container created
+ ID string `json:"id"`
+ // Warnings during container creation
+ Warnings []string `json:"Warnings"`
+}
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index 64d3d378a..2c986db3a 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -6,6 +6,7 @@ import (
"syscall"
"time"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/gorilla/mux"
@@ -83,7 +84,7 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
}
if len(query.Condition) > 0 {
- return 0, errors.Errorf("the condition parameter is not supported")
+ UnSupportedParameter("condition")
}
name := mux.Vars(r)["name"]
@@ -101,3 +102,21 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
}
return con.Wait()
}
+
+// GenerateFilterFuncsFromMap is used to generate un-executed functions that can be used to filter
+// containers. It is specifically designed for the RESTFUL API input.
+func GenerateFilterFuncsFromMap(r *libpod.Runtime, filters map[string][]string) ([]libpod.ContainerFilter, error) {
+ var (
+ filterFuncs []libpod.ContainerFilter
+ )
+ for k, v := range filters {
+ for _, val := range v {
+ f, err := shared.GenerateContainerFilterFuncs(k, val, r)
+ if err != nil {
+ return filterFuncs, err
+ }
+ filterFuncs = append(filterFuncs, f)
+ }
+ }
+ return filterFuncs, nil
+}
diff --git a/pkg/api/handlers/utils/errors.go b/pkg/api/handlers/utils/errors.go
index 3ec0742bd..9d2081cd8 100644
--- a/pkg/api/handlers/utils/errors.go
+++ b/pkg/api/handlers/utils/errors.go
@@ -27,34 +27,34 @@ func Error(w http.ResponseWriter, apiMessage string, code int, err error) {
WriteJSON(w, code, em)
}
-func VolumeNotFound(w http.ResponseWriter, nameOrId string, err error) {
+func VolumeNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchVolume {
InternalServerError(w, err)
}
- msg := fmt.Sprintf("No such volume: %s", nameOrId)
+ msg := fmt.Sprintf("No such volume: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
-func ContainerNotFound(w http.ResponseWriter, nameOrId string, err error) {
+func ContainerNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchCtr {
InternalServerError(w, err)
}
- msg := fmt.Sprintf("No such container: %s", nameOrId)
+ msg := fmt.Sprintf("No such container: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
-func ImageNotFound(w http.ResponseWriter, nameOrId string, err error) {
+func ImageNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchImage {
InternalServerError(w, err)
}
- msg := fmt.Sprintf("No such image: %s", nameOrId)
+ msg := fmt.Sprintf("No such image: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
-func PodNotFound(w http.ResponseWriter, nameOrId string, err error) {
+func PodNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchPod {
InternalServerError(w, err)
}
- msg := fmt.Sprintf("No such pod: %s", nameOrId)
+ msg := fmt.Sprintf("No such pod: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
@@ -73,9 +73,11 @@ func BadRequest(w http.ResponseWriter, key string, value string, err error) {
}
type ErrorModel struct {
- // root cause
+ // API root cause formatted for automated parsing
+ // example: API root cause
Because string `json:"cause"`
- // error message
+ // human error message, formatted for a human to read
+ // example: human error message
Message string `json:"message"`
}
@@ -86,3 +88,8 @@ func (e ErrorModel) Error() string {
func (e ErrorModel) Cause() error {
return errors.New(e.Because)
}
+
+// UnsupportedParameter logs a given param by its string name as not supported.
+func UnSupportedParameter(param string) {
+ log.Infof("API parameter %q: not supported", param)
+}
diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go
index 2fd9bffba..f2ce26f1a 100644
--- a/pkg/api/handlers/utils/handler.go
+++ b/pkg/api/handlers/utils/handler.go
@@ -51,3 +51,11 @@ func WriteJSON(w http.ResponseWriter, code int, value interface{}) {
logrus.Errorf("unable to write json: %q", err)
}
}
+
+func FilterMapToString(filters map[string][]string) (string, error) {
+ f, err := json.Marshal(filters)
+ if err != nil {
+ return "", err
+ }
+ return string(f), nil
+}
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
index 9445298ca..2b651584a 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
+ "github.com/gorilla/mux"
"github.com/gorilla/schema"
)
@@ -15,17 +16,23 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
query := struct {
- //all bool # all is currently unused
- filters []string
- //digests bool # digests is currently unused
+ All bool
+ Filters map[string][]string `schema:"filters"`
+ Digests bool
}{
// This is where you can override the golang default value for one of fields
}
+ // TODO I think all is implemented with a filter?
+
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
return nil, err
}
- filters := query.filters
- if len(filters) < 1 {
+ var filters = []string{}
+ if _, found := mux.Vars(r)["digests"]; found && query.Digests {
+ UnSupportedParameter("digests")
+ }
+
+ if _, found := r.URL.Query()["filters"]; found {
filters = append(filters, fmt.Sprintf("reference=%s", ""))
}
return runtime.ImageRuntime().GetImagesWithFilters(filters)
diff --git a/pkg/api/server/docs.go b/pkg/api/server/docs.go
new file mode 100644
index 000000000..c989c7927
--- /dev/null
+++ b/pkg/api/server/docs.go
@@ -0,0 +1,30 @@
+// Package api Provides a container compatible interface. (Experimental)
+//
+// This documentation describes the HTTP Libpod interface. It is to be considered
+// only as experimental as this point. The endpoints, parameters, inputs, and
+// return values can all change.
+//
+// Terms Of Service:
+//
+// 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/
+//
+// InfoExtensions:
+// x-logo:
+// - url: https://raw.githubusercontent.com/containers/libpod/master/logo/podman-logo.png
+// - altText: "Podman logo"
+//
+// Produces:
+// - application/json
+// - text/plain
+// - text/html
+//
+// Consumes:
+// - application/json
+// - application/x-tar
+// swagger:meta
+package server
diff --git a/pkg/api/server/listener_api.go b/pkg/api/server/listener_api.go
new file mode 100644
index 000000000..4984216b8
--- /dev/null
+++ b/pkg/api/server/listener_api.go
@@ -0,0 +1,31 @@
+package server
+
+import (
+ "net"
+ "os"
+ "path/filepath"
+
+ "github.com/pkg/errors"
+)
+
+// ListenUnix follows stdlib net.Listen() API, providing a unix listener for given path
+// ListenUnix will delete and create files/directories as needed
+func ListenUnix(network string, path string) (net.Listener, error) {
+ // setup custom listener for API server
+ err := os.MkdirAll(filepath.Dir(path), 0770)
+ if err != nil {
+ return nil, errors.Wrapf(err, "api.ListenUnix() failed to create %s", filepath.Dir(path))
+ }
+ os.Remove(path)
+
+ listener, err := net.Listen(network, path)
+ if err != nil {
+ return nil, errors.Wrapf(err, "api.ListenUnix() failed to create net.Listen(%s, %s)", network, path)
+ }
+
+ _, err = os.Stat(path)
+ if err != nil {
+ return nil, errors.Wrapf(err, "net.Listen(%s, %s) failed to report the failure to create socket", network, path)
+ }
+ return listener, nil
+}
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index dbe194cd4..abae81c38 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -23,25 +23,39 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// 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)
+ // 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, handlers.CreateContainer)).Methods(http.MethodPost)
// swagger:operation GET /containers/json compat listContainers
// ---
- // tags:
- // - containers (compat)
+ // tags:
+ // - containers (compat)
// summary: List containers
// description: Returns a list of containers
// parameters:
// - in: query
+ // name: all
+ // type: boolean
+ // default: false
+ // description: Return all containers. By default, only running containers are shown
+ // - in: query
+ // name: limit
+ // description: Return this number of most recently created containers, including non-running ones.
+ // type: integer
+ // - in: query
+ // name: size
+ // type: boolean
+ // default: false
+ // description: Return the size of container as fields SizeRw and SizeRootFs.
+ // - in: query
// name: filters
// type: string
// description: |
@@ -63,17 +77,17 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // "$ref": "#/responses/DocsListContainer"
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 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 compat pruneContainers
// ---
- // tags:
- // - containers (compat)
+ // tags:
+ // - containers (compat)
// summary: Delete stopped containers
// description: Remove containers not in use
// parameters:
@@ -87,76 +101,78 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// 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} compat removeContainer
+ // 200:
+ // $ref: "#/responses/DocsContainerPruneReport"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/prune"), APIHandler(s.Context, handlers.PruneContainers)).Methods(http.MethodPost)
+ // swagger:operation DELETE /containers/{name} compat removeContainer
// ---
- // tags:
- // - containers (compat)
+ // tags:
+ // - containers (compat)
// summary: Remove a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: force
- // type: bool
+ // type: boolean
// default: false
// description: If the container is running, kill it before removing it.
// - in: query
// name: v
- // type: bool
+ // type: boolean
// default: false
// description: Remove the volumes associated with the container.
// - in: query
// name: link
- // type: bool
+ // type: boolean
// description: not supported
// produces:
// - application/json
// responses:
- // '204':
+ // 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 compat getContainer
+ // 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/{name}/json compat getContainer
// ---
- // tags:
- // - containers (compat)
+ // tags:
+ // - containers (compat)
// summary: Inspect container
// description: Return low-level information about a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or id of the container
// - in: query
// name: size
- // type: bool
+ // type: boolean
// 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 compat killcontainer
+ // 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/{name}/kill compat killcontainer
// ---
// tags:
// - containers (compat)
@@ -164,26 +180,29 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Signal to send to the container as an integer or string (e.g. SIGINT)
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: signal
- // type: int
+ // type: string
+ // default: TERM
// description: signal to be sent to container
+ // default: SIGKILL
// produces:
// - application/json
// responses:
- // '204':
+ // 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 compat LogsFromContainer
+ // 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/{name}/logs compat LogsFromContainer
// ---
// tags:
// - containers (compat)
@@ -191,20 +210,21 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Get stdout and stderr logs from a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: follow
- // type: bool
+ // type: boolean
// description: Keep connection after returning logs.
// - in: query
// name: stdout
- // type: bool
+ // type: boolean
// description: not supported
// - in: query
// name: stderr
- // type: bool
+ // type: boolean
// description: not supported?
// - in: query
// name: since
@@ -216,7 +236,7 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Only return logs before this time, as a UNIX timestamp
// - in: query
// name: timestamps
- // type: bool
+ // type: boolean
// default: false
// description: Add timestamps to every log line
// - in: query
@@ -227,14 +247,14 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
+ // 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 compat pauseContainer
+ // 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/{name}/pause compat pauseContainer
// ---
// tags:
// - containers (compat)
@@ -242,71 +262,75 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Use the cgroups freezer to suspend all processes in a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 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 compat restartContainer
+ // 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/{name}/restart compat restartContainer
// ---
// tags:
// - containers (compat)
// summary: Restart container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: t
- // type: int
+ // type: integer
// description: timeout before sending kill signal to container
// produces:
// - application/json
// responses:
- // '204':
+ // 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 compat startContainer
+ // 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/{name}/start compat startContainer
// ---
// tags:
// - containers (compat)
// summary: Start a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: detachKeys
// type: string
- // description: needs description
+ // description: "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _."
+ // default: ctrl-p,ctrl-q
// produces:
// - application/json
// responses:
- // '204':
+ // 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 compat statsContainer
+ // 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/{name}/stats compat statsContainer
// ---
// tags:
// - containers (compat)
@@ -314,58 +338,62 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: This returns a live stream of a container’s resource usage statistics.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: stream
- // type: bool
+ // type: boolean
// 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 compat stopContainer
+ // 200:
+ // description: OK
+ // 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/{name}/stop compat stopContainer
// ---
// tags:
// - containers (compat)
// summary: Stop a container
+ // description: Stop a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: t
- // type: int
+ // type: integer
// description: number of seconds to wait before killing container
// produces:
// - application/json
// responses:
- // '204':
+ // 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 compat topContainer
+ // 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/{name}/top compat topContainer
// ---
// tags:
// - containers (compat)
// summary: List processes running inside a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -375,14 +403,14 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// 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 compat unpauseContainer
+ // 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/{name}/unpause compat unpauseContainer
// ---
// tags:
// - containers (compat)
@@ -390,20 +418,21 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Resume a paused container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 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 compat waitContainer
+ // 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/{name}/wait compat waitContainer
// ---
// tags:
// - containers (compat)
@@ -411,24 +440,25 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Block until a container stops, then returns the exit code.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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
+ // description: not supported
// produces:
// - application/json
// responses:
- // '200':
+ // 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)
- // swagger:operation POST /containers/{nameOrID}/attach compat attach
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/wait"), APIHandler(s.Context, generic.WaitContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{name}/attach compat attach
// ---
// tags:
// - containers (compat)
@@ -436,7 +466,8 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Hijacks the connection to forward the container's standard streams to the client.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -447,42 +478,42 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - in: query
// name: logs
// required: false
- // type: bool
+ // type: boolean
// description: Not yet supported
// - in: query
// name: stream
// required: false
- // type: bool
+ // type: boolean
// default: true
// description: If passed, must be set to true; stream=false is not yet supported
// - in: query
// name: stdout
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDOUT
// - in: query
// name: stderr
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDERR
// - in: query
// name: stdin
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDIN
// produces:
// - application/json
// responses:
- // '101':
+ // 101:
// description: No error, connection has been hijacked for transporting streams.
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/attach"), APIHandler(s.Context, handlers.AttachContainer)).Methods(http.MethodPost)
- // swagger:operation POST /containers/{nameOrID}/resize compat resize
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/attach"), APIHandler(s.Context, handlers.AttachContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{name}/resize compat resize
// ---
// tags:
// - containers (compat)
@@ -490,64 +521,109 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Resize the terminal attached to a container (for use with Attach).
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: h
- // type: int
+ // type: integer
// required: false
// description: Height to set for the terminal, in characters
// - in: query
// name: w
- // type: int
+ // type: integer
// required: false
// description: Width to set for the terminal, in characters
// produces:
// - application/json
// responses:
- // '200':
- // description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/resize"), APIHandler(s.Context, handlers.ResizeContainer)).Methods(http.MethodPost)
+ // 200:
+ // $ref: "#/responses/ok"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/resize"), APIHandler(s.Context, handlers.ResizeContainer)).Methods(http.MethodPost)
/*
libpod endpoints
*/
- r.HandleFunc(VersionedPath("/libpod/containers/create"), APIHandler(s.Context, libpod.CreateContainer)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/create"), APIHandler(s.Context, handlers.CreateContainer)).Methods(http.MethodPost)
// swagger:operation GET /libpod/containers/json libpod libpodListContainers
// ---
// tags:
// - containers
// summary: List containers
// description: Returns a list of containers
+ // parameters:
+ // - in: query
+ // name: all
+ // type: boolean
+ // default: false
+ // description: Return all containers. By default, only running containers are shown
+ // - in: query
+ // name: limit
+ // description: Return this number of most recently created containers, including non-running ones.
+ // type: integer
+ // - in: query
+ // name: namespace
+ // type: boolean
+ // description: Include namespace information
+ // default: false
+ // - in: query
+ // name: pod
+ // type: boolean
+ // default: false
+ // description: Include Pod ID and Name if applicable
+ // - in: query
+ // name: size
+ // type: boolean
+ // default: false
+ // description: Return the size of container as fields SizeRw and SizeRootFs.
+ // - in: query
+ // name: sync
+ // type: boolean
+ // default: false
+ // description: Sync container state with OCI runtime
+ // - 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':
- // schema:
- // "$ref": "#/responses/LibpodListContainersResponse"
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 200:
+ // $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 libpod libpodPruneContainers
+ // swagger:operation POST /libpod/containers/prune libpod libpodPruneContainers
// ---
// tags:
- // - containers
- // summary: Prune unused containers
- // description: Remove stopped and exited containers
+ // - containers
+ // summary: Delete stopped containers
+ // description: Remove containers not in use
// parameters:
// - in: query
- // name: force
- // type: bool
- // description: something
- // - in: query
// name: filters
// type: string
// description: |
@@ -557,11 +633,11 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// 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)
+ // 200:
+ // $ref: "#/responses/DocsLibpodPruneResponse"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/prune"), APIHandler(s.Context, handlers.PruneContainers)).Methods(http.MethodPost)
// swagger:operation GET /libpod/containers/showmounted libpod showMounterContainers
// ---
// tags:
@@ -571,48 +647,50 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: mounted containers
// schema:
// type: object
// additionalProperties:
// type: string
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 500:
+ // $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/showmounted"), APIHandler(s.Context, libpod.ShowMountedContainers)).Methods(http.MethodGet)
- // swagger:operation DELETE /libpod/containers/json libpod libpodRemoveContainer
+ // swagger:operation DELETE /libpod/containers/{name} libpod libpodRemoveContainer
// ---
// tags:
// - containers
// summary: Delete container
+ // description: Delete container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: force
- // type: bool
+ // type: boolean
// description: need something
// - in: query
// name: v
- // type: bool
+ // type: boolean
// description: delete volumes
// produces:
// - application/json
// responses:
- // '204':
+ // 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 libpod libpodGetContainer
+ // 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/{name}/json libpod libpodGetContainer
// ---
// tags:
// - containers
@@ -620,24 +698,25 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Return low-level information about a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: size
- // type: bool
+ // type: boolean
// 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 libpod libpodKillContainer
+ // 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/{name}/kill libpod libpodKillContainer
// ---
// tags:
// - containers
@@ -645,27 +724,28 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: send a signal to a container, defaults to killing the container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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
+ // type: string
+ // default: TERM
+ // description: signal to be sent to container, either by integer or SIG_ name
// produces:
// - application/json
// responses:
- // '204':
+ // 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 libpod mountContainer
+ // 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/{name}/mount libpod mountContainer
// ---
// tags:
// - containers
@@ -673,25 +753,48 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Mount a container to the filesystem
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
+ // 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 libpod libpodPauseContainer
+ // example: /var/lib/containers/storage/overlay/f3f693bd88872a1e3193f4ebb925f4c282e8e73aadb8ab3e7492754dda3a02a4/merged
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/mount"), APIHandler(s.Context, libpod.MountContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/unmount libpod libpodUnmountContainer
+ // ---
+ // tags:
+ // - containers
+ // summary: Unmount a container
+ // description: Unmount a container from the filesystem
+ // produces:
+ // - application/json
+ // parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: the name or ID of the container
+ // responses:
+ // 204:
+ // description: ok
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/unmount"), APIHandler(s.Context, libpod.UnmountContainer)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/logs"), APIHandler(s.Context, libpod.LogsFromContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{name}/pause libpod libpodPauseContainer
// ---
// tags:
// - containers
@@ -699,70 +802,74 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Use the cgroups freezer to suspend all processes in a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 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 libpod libpodRestartContainer
+ // swagger:operation POST /libpod/containers/{name}/restart libpod libpodRestartContainer
// ---
// tags:
// - containers
// summary: Restart a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: t
- // type: int
+ // type: integer
// description: timeout before sending kill signal to container
// produces:
// - application/json
// responses:
- // '204':
+ // 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 libpod libpodStartContainer
+ // 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/{name}/start libpod libpodStartContainer
// ---
// tags:
// - containers
// summary: Start a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: detachKeys
// type: string
- // description: needs description
+ // description: "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _."
+ // default: ctrl-p,ctrl-q
// produces:
// - application/json
// responses:
- // '204':
+ // 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)
- // swagger:operation GET /libpod/containers/{nameOrID}/stats libpod statsContainer
+ // 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)
+ // swagger:operation GET /libpod/containers/{name}/stats libpod libpodStatsContainer
// ---
// tags:
// - containers
@@ -770,98 +877,102 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: This returns a live stream of a container’s resource usage statistics.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: stream
- // type: bool
+ // type: boolean
// default: true
// description: Stream the output
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/stats"), APIHandler(s.Context, generic.StatsContainer)).Methods(http.MethodGet)
- // swagger:operation GET /libpod/containers/{nameOrID}/top containers topContainer
- //
- // List processes running inside a container. Note
- //
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/stats"), APIHandler(s.Context, generic.StatsContainer)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/containers/{name}/top libpod libpodTopContainer
// ---
+ // tags:
+ // - containers
+ // summary: List processes
+ // description: List processes running inside a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
- // description: the name or ID of the container
+ // description: |
+ // Name of container to query for processes
+ // (As of version 1.xx)
// - in: query
// name: stream
- // type: bool
+ // type: boolean
// default: true
// description: Stream the output
+ // - in: query
// name: ps_args
// type: string
+ // default: -ef
// description: arguments to pass to ps such as aux. Requires ps(1) to be installed in the container if no ps(1) compatible AIX descriptors are used.
// produces:
// - application/json
// responses:
- // '200':
- // description: no error
- // "ref": "#/responses/DockerTopResponse"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/containers/{nameOrID}/unpause libpod libpodUnpauseContainer
+ // 200:
+ // $ref: "#/responses/DockerTopResponse"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{name}/unpause libpod libpodUnpauseContainer
// ---
// tags:
// - containers
// summary: Unpause Container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 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 libpod libpodWaitContainer
+ // 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/{name}/wait libpod libpodWaitContainer
// ---
// tags:
// - containers
// summary: Wait on a container to exit
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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':
+ // 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 libpod containerExists
+ // 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/{name}/exists libpod containerExists
// ---
// tags:
// - containers
@@ -869,46 +980,48 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Quick way to determine if a container exists by name or ID
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 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 libpod libpodStopContainer
+ // 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/{name}/stop libpod libpodStopContainer
// ---
// tags:
// - containers
// summary: Stop a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: t
- // type: int
+ // type: integer
// description: number of seconds to wait before killing container
// produces:
// - application/json
// responses:
- // '204':
+ // 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)
- // swagger:operation POST /libpod/containers/{nameOrID}/attach libpod attach
+ // 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)
+ // swagger:operation POST /libpod/containers/{name}/attach libpod libpodAttach
// ---
// tags:
// - containers
@@ -916,7 +1029,8 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Hijacks the connection to forward the container's standard streams to the client.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -927,42 +1041,42 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - in: query
// name: logs
// required: false
- // type: bool
+ // type: boolean
// description: Not yet supported
// - in: query
// name: stream
// required: false
- // type: bool
+ // type: boolean
// default: true
// description: If passed, must be set to true; stream=false is not yet supported
// - in: query
// name: stdout
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDOUT
// - in: query
// name: stderr
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDERR
// - in: query
// name: stdin
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDIN
// produces:
// - application/json
// responses:
- // '101':
+ // 101:
// description: No error, connection has been hijacked for transporting streams.
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/attach"), APIHandler(s.Context, handlers.AttachContainer)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/containers/{nameOrID}/resize libpod resize
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/attach"), APIHandler(s.Context, handlers.AttachContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/resize libpod libpodResize
// ---
// tags:
// - containers
@@ -970,28 +1084,29 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Resize the terminal attached to a container (for use with Attach).
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: h
- // type: int
+ // type: integer
// required: false
// description: Height to set for the terminal, in characters
// - in: query
// name: w
- // type: int
+ // type: integer
// required: false
// description: Width to set for the terminal, in characters
// produces:
// - application/json
// responses:
- // '200':
- // description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/resize"), APIHandler(s.Context, handlers.ResizeContainer)).Methods(http.MethodPost)
+ // 200:
+ // $ref: "#/responses/ok"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/resize"), APIHandler(s.Context, handlers.ResizeContainer)).Methods(http.MethodPost)
return nil
}
diff --git a/pkg/api/server/register_distribution.go b/pkg/api/server/register_distribution.go
index 23820b4a7..b0ac61fb8 100644
--- a/pkg/api/server/register_distribution.go
+++ b/pkg/api/server/register_distribution.go
@@ -6,6 +6,6 @@ import (
)
func (s *APIServer) RegisterDistributionHandlers(r *mux.Router) error {
- r.HandleFunc(VersionedPath("/distribution/{name:..*}/json"), handlers.UnsupportedHandler)
+ 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
index 56cf96de1..a32244f4d 100644
--- a/pkg/api/server/register_events.go
+++ b/pkg/api/server/register_events.go
@@ -8,24 +8,29 @@ import (
func (s *APIServer) RegisterEventsHandlers(r *mux.Router) error {
// swagger:operation GET /events system getEvents
// ---
+ // tags:
+ // - system
// summary: Returns events filtered on query parameters
+ // description: Returns events filtered on query parameters
// produces:
// - application/json
// parameters:
// - name: since
+ // type: string
// in: query
// description: start streaming events from this time
// - name: until
+ // type: string
// in: query
// description: stop streaming events later than this
// - name: filters
+ // type: string
// in: query
// description: JSON encoded map[string][]string of constraints
// responses:
- // "200":
- // description: OK
- // "500":
- // description: Failed
+ // 200:
+ // $ref: "#/responses/ok"
+ // 500:
// "$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
index e4cc145d5..1286324f0 100644
--- a/pkg/api/server/register_healthcheck.go
+++ b/pkg/api/server/register_healthcheck.go
@@ -8,6 +8,6 @@ import (
)
func (s *APIServer) registerHealthCheckHandlers(r *mux.Router) error {
- r.Handle(VersionedPath("/libpod/containers/{name:..*}/runhealthcheck"), APIHandler(s.Context, libpod.RunHealthCheck)).Methods(http.MethodGet)
+ 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
index cd42afe71..c59d3d379 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -11,11 +11,10 @@ import (
func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// swagger:operation POST /images/create compat createImage
- //
// ---
// tags:
// - images (compat)
- // summary: Create an image from an image
+ // summary: Create an image
// description: Create an image by either pulling it from a registry or importing it.
// produces:
// - application/json
@@ -25,53 +24,30 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// 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 createImage
- // ---
- // tags:
- // - images (compat)
- // 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
+ // name: tag
+ // type: string
// description: needs description
+ // - in: header
+ // name: X-Registry-Auth
+ // type: string
+ // description: A base64-encoded auth configuration.
+ // - in: body
+ // name: request
+ // schema:
+ // type: string
+ // description: Image content if fromSrc parameter was used
// 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'
+ // 200:
+ // $ref: "#/responses/ok"
+ // 404:
+ // $ref: "#/responses/NoSuchImage"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}")
r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromSrc)).Methods(http.MethodPost).Queries("fromSrc", "{fromSrc}")
// swagger:operation GET /images/json compat listImages
// ---
@@ -79,20 +55,36 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// - images (compat)
// 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.
+ // parameters:
+ // - name: all
+ // in: query
+ // description: "Show all images. Only images from a final layer (no children) are shown by default."
+ // type: boolean
+ // default: false
+ // - name: filters
+ // in: query
+ // description: |
+ // A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
+ // - `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
+ // - `dangling=true`
+ // - `label=key` or `label="key=value"` of an image label
+ // - `reference`=(`<image-name>[:<tag>]`)
+ // - `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
+ // type: string
+ // - name: digests
+ // in: query
+ // description: Not supported
+ // type: boolean
+ // default: false
// produces:
// - application/json
// responses:
- // '200':
- // schema:
- // type: array
- // items:
- // schema:
- // $ref: "#/responses/DockerImageSummary"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 200:
+ // $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 loadImage
- //
+ // swagger:operation POST /images/load compat importImage
// ---
// tags:
// - images (compat)
@@ -101,20 +93,21 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// parameters:
// - in: query
// name: quiet
- // type: bool
+ // type: boolean
// description: not supported
// - in: body
+ // name: request
// description: tarball of container image
- // type: string
- // format: binary
+ // schema:
+ // type: string
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: no error
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/images/load"), APIHandler(s.Context, handlers.LoadImage)).Methods(http.MethodPost)
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/load"), APIHandler(s.Context, libpod.ImportImage)).Methods(http.MethodPost)
// swagger:operation POST /images/prune compat pruneImages
// ---
// tags:
@@ -135,12 +128,10 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // schema:
- // items:
- // $ref: "#/responses/DocsImageDeleteResponse"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 200:
+ // $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 searchImages
// ---
@@ -155,7 +146,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: term to search
// - in: query
// name: limit
- // type: int
+ // type: integer
// description: maximum number of results
// - in: query
// name: filters
@@ -168,39 +159,44 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // $ref: "#/responses/DocsSearchResponse"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 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 removeImage
+ // swagger:operation DELETE /images/{name} compat removeImage
// ---
// tags:
// - images (compat)
// summary: Remove Image
// description: Delete an image from local storage
// parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: name or ID of image to delete
// - in: query
// name: force
- // type: bool
+ // type: boolean
// description: remove the image even if used by containers or has other tags
// - in: query
// name: noprune
- // type: bool
+ // type: boolean
// 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 exportImage
+ // 200:
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 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/{name}/get compat exportImage
// ---
// tags:
// - images (compat)
@@ -208,21 +204,22 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Export an image in tarball format
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
+ // 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 imageHistory
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/{name}/get"), APIHandler(s.Context, generic.ExportImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/{name}/history compat imageHistory
// ---
// tags:
// - images (compat)
@@ -230,20 +227,21 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Return parent layers of an image.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// $ref: "#/responses/DocsHistory"
- // '404':
+ // 404:
// $ref: "#/responses/NoSuchImage"
- // '500':
+ // 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 inspectImage
+ r.Handle(VersionedPath("/images/{name}/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/{name}/json compat inspectImage
// ---
// tags:
// - images (compat)
@@ -251,20 +249,21 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Return low-level information about an image.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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 tagImage
+ // 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/{name}/tag compat tagImage
// ---
// tags:
// - images (compat)
@@ -272,7 +271,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Tag an image so that it becomes part of a repository.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -296,7 +296,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// $ref: '#/responses/ConflictError'
// 500:
// $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/images/{name:..*}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/images/{name}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
// swagger:operation POST /commit/ compat commitContainer
// ---
// tags:
@@ -325,7 +325,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: author of the image
// - in: query
// name: pause
- // type: bool
+ // type: boolean
// description: pause the container before committing it
// - in: query
// name: changes
@@ -334,19 +334,228 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '201':
+ // 201:
// description: no error
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '500':
- // $ref: '#/responses/InternalError'
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 500:
+ // $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/commit"), APIHandler(s.Context, generic.CommitContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /build images buildImage
+ // ---
+ // tags:
+ // - images
+ // summary: Create image
+ // description: Build an image from the given Dockerfile(s)
+ // parameters:
+ // - in: query
+ // name: dockerfile
+ // type: string
+ // default: Dockerfile
+ // description: |
+ // Path within the build context to the `Dockerfile`.
+ // This is ignored if remote is specified and points to an external `Dockerfile`.
+ // - in: query
+ // name: t
+ // type: string
+ // default: latest
+ // description: A name and optional tag to apply to the image in the `name:tag` format.
+ // - in: query
+ // name: extrahosts
+ // type: string
+ // default:
+ // description: |
+ // TBD Extra hosts to add to /etc/hosts
+ // (As of version 1.xx)
+ // - in: query
+ // name: remote
+ // type: string
+ // default:
+ // description: |
+ // A Git repository URI or HTTP/HTTPS context URI.
+ // If the URI points to a single text file, the file’s contents are placed
+ // into a file called Dockerfile and the image is built from that file. If
+ // the URI points to a tarball, the file is downloaded by the daemon and the
+ // contents therein used as the context for the build. If the URI points to a
+ // tarball and the dockerfile parameter is also specified, there must be a file
+ // with the corresponding path inside the tarball.
+ // (As of version 1.xx)
+ // - in: query
+ // name: q
+ // type: boolean
+ // default: false
+ // description: |
+ // Suppress verbose build output
+ // - in: query
+ // name: nocache
+ // type: boolean
+ // default: false
+ // description: |
+ // Do not use the cache when building the image
+ // (As of version 1.xx)
+ // - in: query
+ // name: cachefrom
+ // type: string
+ // default:
+ // description: |
+ // JSON array of images used to build cache resolution
+ // (As of version 1.xx)
+ // - in: query
+ // name: pull
+ // type: boolean
+ // default: false
+ // description: |
+ // Attempt to pull the image even if an older image exists locally
+ // (As of version 1.xx)
+ // - in: query
+ // name: rm
+ // type: boolean
+ // default: true
+ // description: |
+ // Remove intermediate containers after a successful build
+ // (As of version 1.xx)
+ // - in: query
+ // name: forcerm
+ // type: boolean
+ // default: false
+ // description: |
+ // Always remove intermediate containers, even upon failure
+ // (As of version 1.xx)
+ // - in: query
+ // name: memory
+ // type: integer
+ // description: |
+ // Memory is the upper limit (in bytes) on how much memory running containers can use
+ // (As of version 1.xx)
+ // - in: query
+ // name: memswap
+ // type: integer
+ // description: |
+ // MemorySwap limits the amount of memory and swap together
+ // (As of version 1.xx)
+ // - in: query
+ // name: cpushares
+ // type: integer
+ // description: |
+ // CPUShares (relative weight
+ // (As of version 1.xx)
+ // - in: query
+ // name: cpusetcpus
+ // type: string
+ // description: |
+ // CPUSetCPUs in which to allow execution (0-3, 0,1)
+ // (As of version 1.xx)
+ // - in: query
+ // name: cpuperiod
+ // type: integer
+ // description: |
+ // CPUPeriod limits the CPU CFS (Completely Fair Scheduler) period
+ // (As of version 1.xx)
+ // - in: query
+ // name: cpuquota
+ // type: integer
+ // description: |
+ // CPUQuota limits the CPU CFS (Completely Fair Scheduler) quota
+ // (As of version 1.xx)
+ // - in: query
+ // name: buildargs
+ // type: string
+ // default:
+ // description: |
+ // JSON map of string pairs denoting build-time variables.
+ // For example, the build argument `Foo` with the value of `bar` would be encoded in JSON as `["Foo":"bar"]`.
+ //
+ // For example, buildargs={"Foo":"bar"}.
+ //
+ // Note(s):
+ // * This should not be used to pass secrets.
+ // * The value of buildargs should be URI component encoded before being passed to the API.
+ //
+ // (As of version 1.xx)
+ // - in: query
+ // name: shmsize
+ // type: integer
+ // default: 67108864
+ // description: |
+ // ShmSize is the "size" value to use when mounting an shmfs on the container's /dev/shm directory.
+ // Default is 64MB
+ // (As of version 1.xx)
+ // - in: query
+ // name: squash
+ // type: boolean
+ // default: false
+ // description: |
+ // Silently ignored.
+ // Squash the resulting images layers into a single layer
+ // (As of version 1.xx)
+ // - in: query
+ // name: labels
+ // type: string
+ // default:
+ // description: |
+ // JSON map of key, value pairs to set as labels on the new image
+ // (As of version 1.xx)
+ // - in: query
+ // name: networkmode
+ // type: string
+ // default: bridge
+ // description: |
+ // Sets the networking mode for the run commands during build.
+ // Supported standard values are:
+ // * `bridge` limited to containers within a single host, port mapping required for external access
+ // * `host` no isolation between host and containers on this network
+ // * `none` disable all networking for this container
+ // * container:<nameOrID> share networking with given container
+ // ---All other values are assumed to be a custom network's name
+ // (As of version 1.xx)
+ // - in: query
+ // name: platform
+ // type: string
+ // default:
+ // description: |
+ // Platform format os[/arch[/variant]]
+ // (As of version 1.xx)
+ // - in: query
+ // name: target
+ // type: string
+ // default:
+ // description: |
+ // Target build stage
+ // (As of version 1.xx)
+ // - in: query
+ // name: outputs
+ // type: string
+ // default:
+ // description: |
+ // output configuration TBD
+ // (As of version 1.xx)
+ // produces:
+ // - application/json
+ // responses:
+ // 200:
+ // description: OK (As of version 1.xx)
+ // schema:
+ // type: object
+ // required:
+ // - stream
+ // properties:
+ // stream:
+ // type: string
+ // description: output from build process
+ // example: |
+ // (build details...)
+ // Successfully built 8ba084515c724cbf90d447a63600c0a6
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/build"), APIHandler(s.Context, handlers.BuildImage)).Methods(http.MethodPost)
/*
libpod endpoints
*/
- // swagger:operation POST /libpod/images/{nameOrID}/exists libpod libpodImageExists
+ // swagger:operation POST /libpod/images/{name}/exists libpod libpodImageExists
// ---
// tags:
// - images
@@ -354,21 +563,22 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Check if image exists in local store
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 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 libpod libpodImageHistory
+ // 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/{name}/history libpod libpodImageHistory
// ---
// tags:
// - images
@@ -376,36 +586,56 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Return parent layers of an image.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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)
+ // 200:
+ // $ref: "#/responses/DocsHistory"
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name}/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
// swagger:operation GET /libpod/images/json libpod libpodListImages
// ---
// tags:
// - images
// summary: List Images
// description: Returns a list of images on the server
+ // parameters:
+ // - name: "all"
+ // in: "query"
+ // description: "Show all images. Only images from a final layer (no children) are shown by default."
+ // type: "boolean"
+ // default: false
+ // - name: "filters"
+ // in: "query"
+ // description: |
+ // A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
+ // - `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
+ // - `dangling=true`
+ // - `label=key` or `label="key=value"` of an image label
+ // - `reference`=(`<image-name>[:<tag>]`)
+ // - `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
+ // type: "string"
+ // - name: "digests"
+ // in: "query"
+ // description: Not supported
+ // type: "boolean"
+ // default: false
// produces:
// - application/json
// responses:
- // '200':
- // $ref: "#/responses/DockerImageSummary"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 200:
+ // $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 libpod libpodLoadImage
+ // swagger:operation POST /libpod/images/load libpod libpodImportImage
// ---
// tags:
// - images
@@ -414,20 +644,30 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// parameters:
// - in: query
// name: quiet
- // type: bool
+ // type: boolean
// description: not supported
+ // - in: query
+ // name: change
+ // description: "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR. JSON encoded string"
+ // type: string
+ // - in: query
+ // name: message
+ // description: Set commit message for imported image
+ // type: string
// - in: body
+ // name: request
// description: tarball of container image
- // type: string
- // format: binary
+ // required: true
+ // schema:
+ // type: string
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: no error
- // '500':
+ // 500:
// $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/load"), APIHandler(s.Context, handlers.LoadImage)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/images/load"), APIHandler(s.Context, libpod.ImportImage)).Methods(http.MethodPost)
// swagger:operation POST /libpod/images/prune libpod libpodPruneImages
// ---
// tags:
@@ -445,18 +685,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// (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'
+ // 200:
+ // $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 libpod libpodSearchImages
// ---
@@ -471,7 +706,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: term to search
// - in: query
// name: limit
- // type: int
+ // type: integer
// description: maximum number of results
// - in: query
// name: filters
@@ -484,41 +719,42 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // schema:
- // items:
- // $ref: "#/responses/DocsSearchResponse"
- // '500':
+ // 200:
+ // $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} libpod libpodRemoveImage
+ // swagger:operation DELETE /libpod/images/{name} libpod libpodRemoveImage
// ---
// tags:
// - images
// summary: Remove Image
// description: Delete an image from local store
// parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: name or ID of image to delete
// - in: query
// name: force
- // type: bool
+ // type: boolean
// 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 libpod libpoodExportImage
+ // 200:
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // 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/{name}/get libpod libpoodExportImage
// ---
// tags:
// - images
@@ -526,7 +762,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Export an image as a tarball
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -535,22 +772,22 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: format for exported image
// - in: query
// name: compress
- // type: bool
+ // type: boolean
// description: use compression on image
// produces:
// - application/json
// responses:
- // '200':
+ // 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 libpod libpodInspectImage
+ // 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/{name}/json libpod libpodInspectImage
// ---
// tags:
// - images
@@ -558,20 +795,21 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Obtain low-level information about an image
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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 libpod libpodTagImage
+ // 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/{name}/tag libpod libpodTagImage
// ---
// tags:
// - images
@@ -579,7 +817,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Tag an image so that it becomes part of a repository.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -593,18 +832,17 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '201':
+ // 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)
+ // 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
index a7fb18721..8c50fed7f 100644
--- a/pkg/api/server/register_info.go
+++ b/pkg/api/server/register_info.go
@@ -10,15 +10,17 @@ import (
func (s *APIServer) registerInfoHandlers(r *mux.Router) error {
// swagger:operation GET /info libpod libpodGetInfo
// ---
+ // tags:
+ // - system
// summary: Get info
// description: Returns information on the system and libpod configuration
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: to be determined
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 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_pods.go b/pkg/api/server/register_pods.go
index 5069326b6..5c7b51871 100644
--- a/pkg/api/server/register_pods.go
+++ b/pkg/api/server/register_pods.go
@@ -16,81 +16,79 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// parameters:
// - in: query
// name: filters
- // descriptions: needs description and plumbing for filters
+ // type: string
+ // description: needs description and plumbing for filters
// responses:
- // '200':
- // properties:
- // items:
- // $ref: "#/responses/ListPodsResponse"
- // type: array
- // '400':
- // $ref: "#/responses/BadParamError"
- // '500':
- // $ref: "#/responses/InternalError"
+ // 200:
+ // $ref: "#/responses/ListPodsResponse"
+ // 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"
+ // 200:
+ // description: tbd
+ // schema:
+ // type: object
+ // additionalProperties:
+ // type: string
+ // 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
+ // swagger:operation DELETE /libpod/pods/{name} pods removePod
// ---
// summary: Remove pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// - in: query
// name: force
- // type: bool
- // description: force delete
+ // type: boolean
+ // description : force removal of a running pod by first stopping all containers, then removing all containers in the pod
// 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
+ // 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/{name}/json pods inspectPod
// ---
// summary: Inspect pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// responses:
- // '200':
- // $ref: "#/responses/InspectPodResponse"
- // '404':
+ // 200:
+ // $ref: "#/responses/InspectPodResponse"
+ // 404:
// $ref: "#/responses/NoSuchPod"
- // '500':
+ // 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
+ r.Handle(VersionedPath("/libpod/pods/{name}/json"), APIHandler(s.Context, libpod.PodInspect)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/pods/{name}/exists pods podExists
// ---
// summary: Pod exists
// description: Check if a pod exists by name or ID
@@ -98,142 +96,151 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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
+ // 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/{name}/kill pods killPod
// ---
// summary: Kill a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// - in: query
// name: signal
- // type: int
+ // type: string
// description: signal to be sent to pod
+ // default: SIGKILL
// 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
+ // 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/{name}/pause pods pausePod
// ---
// summary: Pause a pod
+ // description: Pause a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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
+ // 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/{name}/restart pods restartPod
// ---
// summary: Restart a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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
+ // 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/{name}/start pods startPod
// ---
// summary: Start a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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
+ // 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/{name}/stop pods stopPod
// ---
// summary: Stop a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// - in: query
// name: t
- // type: int
+ // type: integer
// 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
+ // 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/{name}/unpause pods unpausePod
// ---
// summary: Unpause a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// 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)
+ // 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_volumes.go b/pkg/api/server/register_volumes.go
index 34138cfbf..d34c71238 100644
--- a/pkg/api/server/register_volumes.go
+++ b/pkg/api/server/register_volumes.go
@@ -31,12 +31,13 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) 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
+ // swagger:operation GET /volumes/{name}/json volumes inspectVolume
// ---
// summary: Inspect volume
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the volume
// produces:
@@ -48,30 +49,31 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error {
// "$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
+ r.Handle("/libpod/volumes/{name}/json", APIHandler(s.Context, libpod.InspectVolume)).Methods(http.MethodGet)
+ // swagger:operation DELETE /volumes/{name} volumes removeVolume
// ---
// summary: Remove volume
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the volume
// - in: query
// name: force
- // type: bool
+ // type: boolean
// 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)
+ // 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
index 2bda5ad01..8c940763e 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -1,32 +1,3 @@
-// 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 (
@@ -40,6 +11,7 @@ import (
"time"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/api/handlers"
"github.com/coreos/go-systemd/activation"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
@@ -48,9 +20,9 @@ import (
)
type APIServer struct {
- http.Server // Where the HTTP work happens
+ http.Server // The HTTP work happens here
*schema.Decoder // Decoder for Query parameters to structs
- context.Context // Context for graceful server shutdown
+ context.Context // Context to carry objects to handlers
*libpod.Runtime // Where the real work happens
net.Listener // mux for routing HTTP API calls to libpod routines
context.CancelFunc // Stop APIServer
@@ -58,14 +30,37 @@ type APIServer struct {
time.Duration // Duration of client access sliding window
}
-// NewServer will create and configure a new API HTTP server
+// Number of seconds to wait for next request, if exceeded shutdown server
+const (
+ DefaultServiceDuration = 300 * time.Second
+ UnlimitedServiceDuration = 0 * time.Second
+)
+
+// NewServer will create and configure a new API server with all defaults
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))
+ return newServer(runtime, DefaultServiceDuration, nil)
+}
+
+// NewServerWithSettings will create and configure a new API server using provided settings
+func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
+ return newServer(runtime, duration, listener)
+}
+
+func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
+ // If listener not provided try socket activation protocol
+ if listener == nil {
+ if _, found := os.LookupEnv("LISTEN_FDS"); !found {
+ return nil, errors.Errorf("Cannot create Server, no listener provided and socket activation protocol is not active.")
+ }
+
+ 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 for socket activation protocol (%d != 1)", len(listeners))
+ }
+ listener = &listeners[0]
}
router := mux.NewRouter()
@@ -77,12 +72,12 @@ func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
ReadTimeout: 20 * time.Second,
WriteTimeout: 2 * time.Minute,
},
- Decoder: schema.NewDecoder(),
+ Decoder: handlers.NewAPIDecoder(),
Context: nil,
Runtime: runtime,
- Listener: listeners[0],
+ Listener: *listener,
CancelFunc: nil,
- Duration: 300 * time.Second,
+ Duration: duration,
}
server.Timer = time.AfterFunc(server.Duration, func() {
if err := server.Shutdown(); err != nil {
@@ -91,6 +86,7 @@ func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
})
ctx, cancelFn := context.WithCancel(context.Background())
+ server.CancelFunc = cancelFn
// TODO: Use ConnContext when ported to go 1.13
ctx = context.WithValue(ctx, "decoder", server.Decoder)
@@ -98,9 +94,6 @@ func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
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...
@@ -176,6 +169,11 @@ func (s *APIServer) Serve() error {
// Shutdown is a clean shutdown waiting on existing clients
func (s *APIServer) Shutdown() error {
+ // Duration == 0 flags no auto-shutdown of server
+ if s.Duration == 0 {
+ return nil
+ }
+
// We're still in the sliding service window
if s.Timer.Stop() {
s.Timer.Reset(s.Duration)
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
index dbf499ce7..5098390bc 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -41,7 +41,7 @@ type swagErrNoSuchPod struct {
}
}
-// Internal error
+// Internal server error
// swagger:response InternalError
type swagInternalError struct {
// in:body
@@ -50,16 +50,7 @@ type swagInternalError struct {
}
}
-// Generic error
-// swagger:response GenericError
-type swagGenericError struct {
- // in:body
- Body struct {
- utils.ErrorModel
- }
-}
-
-// Conflict error
+// Conflict error in operation
// swagger:response ConflictError
type swagConflictError struct {
// in:body
@@ -68,7 +59,7 @@ type swagConflictError struct {
}
}
-// Bad parameter
+// Bad parameter in request
// swagger:response BadParamError
type swagBadParamError struct {
// in:body
@@ -130,7 +121,12 @@ type swagListContainers struct {
}
}
-// To be determined
-// swagger:response tbd
-type swagTBD struct {
+// Success
+// swagger:response
+type ok struct {
+ // in:body
+ Body struct {
+ // example: OK
+ ok string
+ }
}