summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common.go2
-rw-r--r--cmd/podman/shared/create.go6
-rw-r--r--docs/source/markdown/podman-create.1.md2
-rw-r--r--docs/source/markdown/podman-run.1.md2
-rw-r--r--go.mod2
-rw-r--r--libpod/runtime_ctr.go41
-rw-r--r--pkg/api/handlers/containers.go53
-rw-r--r--pkg/api/handlers/decoder.go91
-rw-r--r--pkg/api/handlers/events.go25
-rw-r--r--pkg/api/handlers/generic/containers.go80
-rw-r--r--pkg/api/handlers/generic/containers_create.go4
-rw-r--r--pkg/api/handlers/generic/images.go17
-rw-r--r--pkg/api/handlers/handler.go9
-rw-r--r--pkg/api/handlers/libpod/containers.go42
-rw-r--r--pkg/api/handlers/libpod/images.go22
-rw-r--r--pkg/api/handlers/libpod/pods.go12
-rw-r--r--pkg/api/handlers/swagger.go7
-rw-r--r--pkg/api/handlers/types.go6
-rw-r--r--pkg/api/handlers/utils/containers.go21
-rw-r--r--pkg/api/handlers/utils/handler.go8
-rw-r--r--pkg/api/handlers/utils/images.go11
-rw-r--r--pkg/api/server/register_containers.go96
-rw-r--r--pkg/api/server/server.go7
-rw-r--r--pkg/api/server/swagger.go24
-rw-r--r--pkg/bindings/bindings.go9
-rw-r--r--pkg/util/camelcase/LICENSE.md (renamed from vendor/github.com/fatih/camelcase/LICENSE.md)0
-rw-r--r--pkg/util/camelcase/README.md (renamed from vendor/github.com/fatih/camelcase/README.md)0
-rw-r--r--pkg/util/camelcase/camelcase.go (renamed from vendor/github.com/fatih/camelcase/camelcase.go)5
-rw-r--r--test/e2e/config.go4
-rw-r--r--vendor/github.com/fatih/camelcase/.travis.yml3
-rw-r--r--vendor/modules.txt2
31 files changed, 434 insertions, 179 deletions
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index f3aff1d49..46feae90d 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -12,7 +12,7 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/sysinfo"
- "github.com/fatih/camelcase"
+ "github.com/containers/libpod/pkg/util/camelcase"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 15d6bddbb..2f637694b 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -31,9 +31,9 @@ import (
"github.com/sirupsen/logrus"
)
-// seccompAnnotationKey is the key of the image annotation embedding a seccomp
+// seccompLabelKey is the key of the image annotation embedding a seccomp
// profile.
-const seccompAnnotationKey = "io.containers.seccomp.profile"
+const seccompLabelKey = "io.containers.seccomp.profile"
func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) {
var (
@@ -709,7 +709,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
// SECCOMP
if data != nil {
- if value, exists := data.Annotations[seccompAnnotationKey]; exists {
+ if value, exists := labels[seccompLabelKey]; exists {
secConfig.SeccompProfileFromImage = value
}
}
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 7f0c2260c..0e641f3a3 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -679,7 +679,7 @@ of the container is assumed to be managed externally.
**--seccomp-policy**=*policy*
-Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" annotation in the container image and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
+Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
Note that this feature is experimental and may change in the future.
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 2b1452b53..512a382a6 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -700,7 +700,7 @@ Note: On `SELinux` systems, the rootfs needs the correct label, which is by defa
**--seccomp-policy**=*policy*
-Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" annotation in the container image and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
+Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
Note that this feature is experimental and may change in the future.
diff --git a/go.mod b/go.mod
index 58aa30b5a..59888cfc3 100644
--- a/go.mod
+++ b/go.mod
@@ -29,7 +29,7 @@ require (
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
github.com/elazarl/goproxy/ext v0.0.0-20190911111923-ecfe977594f1 // indirect
github.com/etcd-io/bbolt v1.3.3
- github.com/fatih/camelcase v1.0.0
+ github.com/fatih/camelcase v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.4.7
github.com/ghodss/yaml v1.0.0
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index de7cfd3b8..e8952967d 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -836,3 +836,44 @@ func (r *Runtime) GetLatestContainer() (*Container, error) {
}
return ctrs[lastCreatedIndex], nil
}
+
+// PruneContainers removes stopped and exited containers from localstorage. A set of optional filters
+// can be provided to be more granular.
+func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int64, map[string]error, error) {
+ pruneErrors := make(map[string]error)
+ prunedContainers := make(map[string]int64)
+ // We add getting the exited and stopped containers via a filter
+ containerStateFilter := func(c *Container) bool {
+ if c.PodID() != "" {
+ return false
+ }
+ state, err := c.State()
+ if err != nil {
+ logrus.Error(err)
+ return false
+ }
+ if state == define.ContainerStateStopped || state == define.ContainerStateExited {
+ return true
+ }
+ return false
+ }
+ filterFuncs = append(filterFuncs, containerStateFilter)
+ delContainers, err := r.GetContainers(filterFuncs...)
+ if err != nil {
+ return nil, nil, err
+ }
+ for _, c := range delContainers {
+ ctr := c
+ size, err := ctr.RWSize()
+ if err != nil {
+ pruneErrors[ctr.ID()] = err
+ continue
+ }
+ err = r.RemoveContainer(context.Background(), ctr, false, false)
+ pruneErrors[ctr.ID()] = err
+ if err != nil {
+ prunedContainers[ctr.ID()] = size
+ }
+ }
+ return prunedContainers, pruneErrors, nil
+}
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/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/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/containers_create.go b/pkg/api/handlers/generic/containers_create.go
index f98872690..edefd5757 100644
--- a/pkg/api/handlers/generic/containers_create.go
+++ b/pkg/api/handlers/generic/containers_create.go
@@ -40,7 +40,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()"))
diff --git a/pkg/api/handlers/generic/images.go b/pkg/api/handlers/generic/images.go
index 395f64064..93adb7f69 100644
--- a/pkg/api/handlers/generic/images.go
+++ b/pkg/api/handlers/generic/images.go
@@ -62,14 +62,14 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
// 200 no error
// 500 internal
var (
- dangling bool = true
+ dangling = true
err error
)
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,26 +79,25 @@ 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"))
+ if v, found := query.Filters["until"]; found {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "until=%s is not supported yet", v))
return
}
// labels are not supported on podman prune
- if len(query.filters["label"]) > 0 {
+ if _, found := query.Filters["since"]; found {
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 v, found := query.Filters["dangling"]; found {
+ dangling, err = strconv.ParseBool(v[0])
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "processing dangling filter"))
return
}
}
+
idr := []types.ImageDeleteResponseItem{}
//
// This code needs to be migrated to libpod to work correctly. I could not
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/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index e16a4ea1f..df16843c7 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"
@@ -46,12 +48,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 +71,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 +132,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) {
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 0d4e220a8..bbc8c9346 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -1,6 +1,7 @@
package libpod
import (
+ "fmt"
"io/ioutil"
"net/http"
"os"
@@ -42,12 +43,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)
@@ -95,8 +96,8 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- All bool `schema:"all"`
- Filters []string `schema:"filters"`
+ All bool `schema:"all"`
+ Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}
@@ -106,7 +107,14 @@ 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 {
+ for k, v := range query.Filters {
+ libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
+ }
+ }
+ cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 14f8e8de7..656a75646 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)
}
diff --git a/pkg/api/handlers/swagger.go b/pkg/api/handlers/swagger.go
index 5509c1d46..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 {
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 2526a3317..33cd51164 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
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/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..a0d340471 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -15,17 +15,18 @@ 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 # all is currently unused
+ Filters map[string][]string `schema:"filters"`
+ // digests bool # digests 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 {
return nil, err
}
- filters := query.filters
- if len(filters) < 1 {
+
+ var filters = []string{}
+ 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/register_containers.go b/pkg/api/server/register_containers.go
index 58920d106..b2d2ab388 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -42,6 +42,20 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// 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: |
@@ -91,7 +105,7 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// $ref: "#/responses/DocsContainerPruneReport"
// 500:
// $ref: "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/prune"), APIHandler(s.Context, generic.PruneContainers)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/containers/prune"), APIHandler(s.Context, handlers.PruneContainers)).Methods(http.MethodPost)
// swagger:operation DELETE /containers/{name} compat removeContainer
// ---
// tags:
@@ -175,6 +189,7 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// type: string
// default: TERM
// description: signal to be sent to container
+ // default: SIGKILL
// produces:
// - application/json
// responses:
@@ -301,7 +316,8 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - 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:
@@ -431,7 +447,7 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - in: query
// name: condition
// type: string
- // description: Wait until the container reaches the given condition
+ // description: not supported
// produces:
// - application/json
// responses:
@@ -541,6 +557,55 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - 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:
@@ -551,18 +616,14 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// 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: boolean
- // description: TODO This should be removed from API. Will always be true...
- // - in: query
// name: filters
// type: string
// description: |
@@ -573,12 +634,10 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - application/json
// responses:
// 200:
- // type: string
- // description: success
- // example: OK
+ // $ref: "#/responses/DocsLibpodPruneResponse"
// 500:
// $ref: "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/prune"), APIHandler(s.Context, libpod.PruneContainers)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/prune"), APIHandler(s.Context, handlers.PruneContainers)).Methods(http.MethodPost)
// swagger:operation GET /libpod/containers/showmounted libpod showMounterContainers
// ---
// tags:
@@ -796,7 +855,8 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - 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:
@@ -902,10 +962,6 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// 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:
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 847d11c3c..8c940763e 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -11,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"
@@ -71,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,
@@ -85,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)
@@ -92,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 f6643600a..5098390bc 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -50,15 +50,6 @@ type swagInternalError struct {
}
}
-// Generic error
-// swagger:response GenericError
-type swagGenericError struct {
- // in:body
- Body struct {
- utils.ErrorModel
- }
-}
-
// Conflict error in operation
// swagger:response ConflictError
type swagConflictError struct {
@@ -130,21 +121,6 @@ type swagListContainers struct {
}
}
-// To be determined
-// swagger:response tbd
-type swagTBD struct {
-}
-
-// Success
-// swagger:response
-type swag struct {
- // in:body
- Body struct {
- // example: OK
- ok string
- }
-}
-
// Success
// swagger:response
type ok struct {
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/vendor/github.com/fatih/camelcase/LICENSE.md b/pkg/util/camelcase/LICENSE.md
index aa4a536ca..aa4a536ca 100644
--- a/vendor/github.com/fatih/camelcase/LICENSE.md
+++ b/pkg/util/camelcase/LICENSE.md
diff --git a/vendor/github.com/fatih/camelcase/README.md b/pkg/util/camelcase/README.md
index 105a6ae33..105a6ae33 100644
--- a/vendor/github.com/fatih/camelcase/README.md
+++ b/pkg/util/camelcase/README.md
diff --git a/vendor/github.com/fatih/camelcase/camelcase.go b/pkg/util/camelcase/camelcase.go
index 02160c9a4..0a82d1005 100644
--- a/vendor/github.com/fatih/camelcase/camelcase.go
+++ b/pkg/util/camelcase/camelcase.go
@@ -55,7 +55,7 @@ func Split(src string) (entries []string) {
class := 0
// split into fields based on class of unicode character
for _, r := range src {
- switch true {
+ switch {
case unicode.IsLower(r):
class = 1
case unicode.IsUpper(r):
@@ -86,5 +86,6 @@ func Split(src string) (entries []string) {
entries = append(entries, string(s))
}
}
- return
+
+ return entries
}
diff --git a/test/e2e/config.go b/test/e2e/config.go
index 12d0e545e..96cc157be 100644
--- a/test/e2e/config.go
+++ b/test/e2e/config.go
@@ -19,8 +19,8 @@ var (
// The intention behind blocking all syscalls is to prevent
// regressions in the future. The required syscalls can vary
// depending on which runtime we're using.
- alpineSeccomp = "docker.io/libpod/alpine-with-seccomp:latest"
+ alpineSeccomp = "docker.io/libpod/alpine-with-seccomp:label"
// This image has a bogus/invalid seccomp profile which should
// yield a json error when being read.
- alpineBogusSeccomp = "docker.io/libpod/alpine-with-bogus-seccomp:latest"
+ alpineBogusSeccomp = "docker.io/libpod/alpine-with-bogus-seccomp:label"
)
diff --git a/vendor/github.com/fatih/camelcase/.travis.yml b/vendor/github.com/fatih/camelcase/.travis.yml
deleted file mode 100644
index 3489e3871..000000000
--- a/vendor/github.com/fatih/camelcase/.travis.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-language: go
-go: 1.x
-
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 2aa86270a..e28bbd41d 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -261,8 +261,6 @@ github.com/docker/spdystream
github.com/docker/spdystream/spdy
# github.com/etcd-io/bbolt v1.3.3
github.com/etcd-io/bbolt
-# github.com/fatih/camelcase v1.0.0
-github.com/fatih/camelcase
# github.com/fsnotify/fsnotify v1.4.7
github.com/fsnotify/fsnotify
# github.com/fsouza/go-dockerclient v1.6.0