diff options
Diffstat (limited to 'pkg')
37 files changed, 1497 insertions, 1074 deletions
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index 5891c361f..f89fc7011 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -58,9 +58,9 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal } logrus.Debugf("Setting maximum rm workers to %d", maxWorkers) - states := []string{shared.PodStateStopped, shared.PodStateExited} + states := []string{define.PodStateStopped, define.PodStateExited} if cli.Force { - states = append(states, shared.PodStateRunning) + states = append(states, define.PodStateRunning) } pods, err := r.GetPodsByStatus(states) diff --git a/pkg/adapter/pods_remote.go b/pkg/adapter/pods_remote.go index 16d34769e..5ef1a9216 100644 --- a/pkg/adapter/pods_remote.go +++ b/pkg/adapter/pods_remote.go @@ -540,9 +540,9 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal ok = []string{} failures = map[string]error{} ) - states := []string{shared.PodStateStopped, shared.PodStateExited} + states := []string{define.PodStateStopped, define.PodStateExited} if cli.Force { - states = append(states, shared.PodStateRunning) + states = append(states, define.PodStateRunning) } ids, err := iopodman.GetPodsByStatus().Call(r.Conn, states) diff --git a/pkg/api/Makefile b/pkg/api/Makefile index 915f0b9b3..f564b6516 100644 --- a/pkg/api/Makefile +++ b/pkg/api/Makefile @@ -2,12 +2,12 @@ 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} -w ./ + swagger generate spec -o ${SWAGGER_OUT} -i tags.yaml -w ./ -# TODO: when pass validation move it under swagger. -validate: - swagger validate ${SWAGGER_OUT} 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 4f303f6ab..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") } diff --git a/pkg/api/handlers/images.go b/pkg/api/handlers/images.go index b4acdc312..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" @@ -127,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/libpod/containers.go b/pkg/api/handlers/libpod/containers.go index e16a4ea1f..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,6 @@ 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"] 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 14f8e8de7..50d763338 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -108,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 } @@ -117,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) @@ -164,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 } @@ -207,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) } @@ -266,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 } @@ -282,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 } @@ -307,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) { diff --git a/pkg/api/handlers/swagger.go b/pkg/api/handlers/swagger.go index 0db4e19b6..faae98798 100644 --- a/pkg/api/handlers/swagger.go +++ b/pkg/api/handlers/swagger.go @@ -58,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 { @@ -96,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 b6f125c58..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"` } 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/register_containers.go b/pkg/api/server/register_containers.go index 833bb5197..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 POST /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,46 +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: /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 GET /libpod/containers/{nameOrID}/unmount libpod unmountContainer + // 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: nameOrID + // name: name + // type: string // required: true // description: the name or ID of the container - // produces: - // - application/json // responses: - // '204': - // description: no error - // '404': - // "$ref": "#/responses/NoSuchContainer" - // '500': - // "$ref": "#/responses/InternalError" - r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/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/{nameOrID}/pause libpod libpodPauseContainer + // 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 @@ -720,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 @@ -791,99 +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 libpod libpodTopContainer - // - // 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': - // "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 @@ -891,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 @@ -938,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 @@ -949,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 @@ -992,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 8ea079654..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" - // '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/{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,12 +334,12 @@ 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 @@ -534,23 +534,28 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // description: OK (As of version 1.xx) - // schema: - // type: object - // required: - // - stream - // properties: - // stream: - // type: string - // example: | - // (build details...) - // Successfully built 8ba084515c724cbf90d447a63600c0a6 + // 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 @@ -558,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 @@ -580,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 @@ -618,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: @@ -649,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 // --- @@ -675,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 @@ -688,37 +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': - // $ref: "#/responses/DocsImageDeleteResponse" - // '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 @@ -726,33 +762,32 @@ 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 // name: format // type: string // description: format for exported image - // default: oci-archive // - in: query // name: compress - // type: bool + // type: boolean // description: use compression on image - // default: false // 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 @@ -760,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 @@ -781,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 @@ -795,17 +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) 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 4018cfbe8..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,25 +96,27 @@ 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 @@ -125,116 +125,122 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error { // 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 69a44f21a..8c940763e 100644 --- a/pkg/api/server/server.go +++ b/pkg/api/server/server.go @@ -1,44 +1,3 @@ -// Package api Provides a container compatible interface. -// -// This documentation describes the HTTP Libpod interface. It is to be consider -// only as experimental as this point. The endpoints, parameters, inputs, and -// return values can all change. -// -// 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" -// -// Consumes: -// - application/json -// - application/x-tar -// -// Produces: -// - application/json -// - text/plain -// - text/html -// -// tags: -// - name: containers -// description: Actions related to containers -// - name: images -// description: Actions related to images -// - name: pods -// description: Actions related to pods -// - name: volumes -// description: Actions related to volumes -// - name: containers (compat) -// description: Actions related to containers for the compatibility endpoints -// - name: images (compat) -// description: Actions related to images for the compatibility endpoints -// -// swagger:meta package server import ( @@ -52,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" @@ -112,7 +72,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li ReadTimeout: 20 * time.Second, WriteTimeout: 2 * time.Minute, }, - Decoder: schema.NewDecoder(), + Decoder: handlers.NewAPIDecoder(), Context: nil, Runtime: runtime, Listener: *listener, @@ -126,6 +86,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li }) 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) @@ -133,9 +94,6 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li 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... 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 + } } diff --git a/pkg/bindings/bindings.go b/pkg/bindings/bindings.go new file mode 100644 index 000000000..e83c4a5e1 --- /dev/null +++ b/pkg/bindings/bindings.go @@ -0,0 +1,9 @@ +// Package bindings provides golang-based access +// to the Podman REST API. Users can then interact with API endpoints +// to manage containers, images, pods, etc. +// +// This package exposes a series of methods that allow users to firstly +// create their connection with the API endpoints. Once the connection +// is established, users can then manage the Podman container runtime. + +package bindings diff --git a/pkg/util/camelcase/LICENSE.md b/pkg/util/camelcase/LICENSE.md new file mode 100644 index 000000000..aa4a536ca --- /dev/null +++ b/pkg/util/camelcase/LICENSE.md @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2015 Fatih Arslan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/pkg/util/camelcase/README.md b/pkg/util/camelcase/README.md new file mode 100644 index 000000000..105a6ae33 --- /dev/null +++ b/pkg/util/camelcase/README.md @@ -0,0 +1,58 @@ +# CamelCase [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/camelcase) [![Build Status](http://img.shields.io/travis/fatih/camelcase.svg?style=flat-square)](https://travis-ci.org/fatih/camelcase) + +CamelCase is a Golang (Go) package to split the words of a camelcase type +string into a slice of words. It can be used to convert a camelcase word (lower +or upper case) into any type of word. + +## Splitting rules: + +1. If string is not valid UTF-8, return it without splitting as + single item array. +2. Assign all unicode characters into one of 4 sets: lower case + letters, upper case letters, numbers, and all other characters. +3. Iterate through characters of string, introducing splits + between adjacent characters that belong to different sets. +4. Iterate through array of split strings, and if a given string + is upper case: + * if subsequent string is lower case: + * move last character of upper case string to beginning of + lower case string + +## Install + +```bash +go get github.com/fatih/camelcase +``` + +## Usage and examples + +```go +splitted := camelcase.Split("GolangPackage") + +fmt.Println(splitted[0], splitted[1]) // prints: "Golang", "Package" +``` + +Both lower camel case and upper camel case are supported. For more info please +check: [http://en.wikipedia.org/wiki/CamelCase](http://en.wikipedia.org/wiki/CamelCase) + +Below are some example cases: + +``` +"" => [] +"lowercase" => ["lowercase"] +"Class" => ["Class"] +"MyClass" => ["My", "Class"] +"MyC" => ["My", "C"] +"HTML" => ["HTML"] +"PDFLoader" => ["PDF", "Loader"] +"AString" => ["A", "String"] +"SimpleXMLParser" => ["Simple", "XML", "Parser"] +"vimRPCPlugin" => ["vim", "RPC", "Plugin"] +"GL11Version" => ["GL", "11", "Version"] +"99Bottles" => ["99", "Bottles"] +"May5" => ["May", "5"] +"BFG9000" => ["BFG", "9000"] +"BöseÜberraschung" => ["Böse", "Überraschung"] +"Two spaces" => ["Two", " ", "spaces"] +"BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"] +``` diff --git a/pkg/util/camelcase/camelcase.go b/pkg/util/camelcase/camelcase.go new file mode 100644 index 000000000..0a82d1005 --- /dev/null +++ b/pkg/util/camelcase/camelcase.go @@ -0,0 +1,91 @@ +// Package camelcase is a micro package to split the words of a camelcase type +// string into a slice of words. +package camelcase + +import ( + "unicode" + "unicode/utf8" +) + +// Split splits the camelcase word and returns a list of words. It also +// supports digits. Both lower camel case and upper camel case are supported. +// For more info please check: http://en.wikipedia.org/wiki/CamelCase +// +// Examples +// +// "" => [""] +// "lowercase" => ["lowercase"] +// "Class" => ["Class"] +// "MyClass" => ["My", "Class"] +// "MyC" => ["My", "C"] +// "HTML" => ["HTML"] +// "PDFLoader" => ["PDF", "Loader"] +// "AString" => ["A", "String"] +// "SimpleXMLParser" => ["Simple", "XML", "Parser"] +// "vimRPCPlugin" => ["vim", "RPC", "Plugin"] +// "GL11Version" => ["GL", "11", "Version"] +// "99Bottles" => ["99", "Bottles"] +// "May5" => ["May", "5"] +// "BFG9000" => ["BFG", "9000"] +// "BöseÜberraschung" => ["Böse", "Überraschung"] +// "Two spaces" => ["Two", " ", "spaces"] +// "BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"] +// +// Splitting rules +// +// 1) If string is not valid UTF-8, return it without splitting as +// single item array. +// 2) Assign all unicode characters into one of 4 sets: lower case +// letters, upper case letters, numbers, and all other characters. +// 3) Iterate through characters of string, introducing splits +// between adjacent characters that belong to different sets. +// 4) Iterate through array of split strings, and if a given string +// is upper case: +// if subsequent string is lower case: +// move last character of upper case string to beginning of +// lower case string +func Split(src string) (entries []string) { + // don't split invalid utf8 + if !utf8.ValidString(src) { + return []string{src} + } + entries = []string{} + var runes [][]rune + lastClass := 0 + class := 0 + // split into fields based on class of unicode character + for _, r := range src { + switch { + case unicode.IsLower(r): + class = 1 + case unicode.IsUpper(r): + class = 2 + case unicode.IsDigit(r): + class = 3 + default: + class = 4 + } + if class == lastClass { + runes[len(runes)-1] = append(runes[len(runes)-1], r) + } else { + runes = append(runes, []rune{r}) + } + lastClass = class + } + // handle upper case -> lower case sequences, e.g. + // "PDFL", "oader" -> "PDF", "Loader" + for i := 0; i < len(runes)-1; i++ { + if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) { + runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...) + runes[i] = runes[i][:len(runes[i])-1] + } + } + // construct []string from results + for _, s := range runes { + if len(s) > 0 { + entries = append(entries, string(s)) + } + } + + return entries +} |