summaryrefslogtreecommitdiff
path: root/pkg/api/handlers/utils
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/api/handlers/utils')
-rw-r--r--pkg/api/handlers/utils/containers.go103
-rw-r--r--pkg/api/handlers/utils/errors.go88
-rw-r--r--pkg/api/handlers/utils/handler.go44
-rw-r--r--pkg/api/handlers/utils/images.go32
4 files changed, 267 insertions, 0 deletions
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
new file mode 100644
index 000000000..64d3d378a
--- /dev/null
+++ b/pkg/api/handlers/utils/containers.go
@@ -0,0 +1,103 @@
+package utils
+
+import (
+ "fmt"
+ "net/http"
+ "syscall"
+ "time"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/gorilla/mux"
+ "github.com/gorilla/schema"
+ "github.com/pkg/errors"
+)
+
+func KillContainer(w http.ResponseWriter, r *http.Request) (*libpod.Container, error) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decorder").(*schema.Decoder)
+ query := struct {
+ Signal syscall.Signal `schema:"signal"`
+ }{
+ Signal: syscall.SIGKILL,
+ }
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return nil, err
+ }
+ name := mux.Vars(r)["name"]
+ con, err := runtime.LookupContainer(name)
+ if err != nil {
+ ContainerNotFound(w, name, err)
+ return nil, err
+ }
+
+ state, err := con.State()
+ if err != nil {
+ InternalServerError(w, err)
+ return con, err
+ }
+
+ // If the Container is stopped already, send a 409
+ if state == define.ContainerStateStopped || state == define.ContainerStateExited {
+ Error(w, fmt.Sprintf("Container %s is not running", name), http.StatusConflict, errors.New(fmt.Sprintf("Cannot kill Container %s, it is not running", name)))
+ return con, err
+ }
+
+ err = con.Kill(uint(query.Signal))
+ if err != nil {
+ Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "unable to kill Container %s", name))
+ }
+ return con, err
+}
+
+func RemoveContainer(w http.ResponseWriter, r *http.Request, force, vols bool) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ name := mux.Vars(r)["name"]
+ con, err := runtime.LookupContainer(name)
+ if err != nil {
+ ContainerNotFound(w, name, err)
+ return
+ }
+
+ if err := runtime.RemoveContainer(r.Context(), con, force, vols); err != nil {
+ InternalServerError(w, err)
+ return
+ }
+ WriteResponse(w, http.StatusNoContent, "")
+}
+
+func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ // /{version}/containers/(name)/restart
+ query := struct {
+ Interval string `schema:"interval"`
+ Condition string `schema:"condition"`
+ }{
+ // Override golang default values for types
+ }
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return 0, err
+ }
+
+ if len(query.Condition) > 0 {
+ return 0, errors.Errorf("the condition parameter is not supported")
+ }
+
+ name := mux.Vars(r)["name"]
+ con, err := runtime.LookupContainer(name)
+ if err != nil {
+ ContainerNotFound(w, name, err)
+ return 0, err
+ }
+ if len(query.Interval) > 0 {
+ d, err := time.ParseDuration(query.Interval)
+ if err != nil {
+ Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %s for interval", query.Interval))
+ }
+ return con.WaitWithInterval(d)
+ }
+ return con.Wait()
+}
diff --git a/pkg/api/handlers/utils/errors.go b/pkg/api/handlers/utils/errors.go
new file mode 100644
index 000000000..3ec0742bd
--- /dev/null
+++ b/pkg/api/handlers/utils/errors.go
@@ -0,0 +1,88 @@
+package utils
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/containers/libpod/libpod/define"
+ "github.com/pkg/errors"
+ log "github.com/sirupsen/logrus"
+)
+
+var (
+ ErrLinkNotSupport = errors.New("Link is not supported")
+)
+
+// Error formats an API response to an error
+//
+// apiMessage and code must match the container API, and are sent to client
+// err is logged on the system running the podman service
+func Error(w http.ResponseWriter, apiMessage string, code int, err error) {
+ // Log detailed message of what happened to machine running podman service
+ log.Infof("Request Failed(%s): %s", http.StatusText(code), err.Error())
+ em := ErrorModel{
+ Because: (errors.Cause(err)).Error(),
+ Message: err.Error(),
+ }
+ WriteJSON(w, code, em)
+}
+
+func VolumeNotFound(w http.ResponseWriter, nameOrId string, err error) {
+ if errors.Cause(err) != define.ErrNoSuchVolume {
+ InternalServerError(w, err)
+ }
+ msg := fmt.Sprintf("No such volume: %s", nameOrId)
+ Error(w, msg, http.StatusNotFound, err)
+}
+func ContainerNotFound(w http.ResponseWriter, nameOrId string, err error) {
+ if errors.Cause(err) != define.ErrNoSuchCtr {
+ InternalServerError(w, err)
+ }
+ msg := fmt.Sprintf("No such container: %s", nameOrId)
+ Error(w, msg, http.StatusNotFound, err)
+}
+
+func ImageNotFound(w http.ResponseWriter, nameOrId string, err error) {
+ if errors.Cause(err) != define.ErrNoSuchImage {
+ InternalServerError(w, err)
+ }
+ msg := fmt.Sprintf("No such image: %s", nameOrId)
+ Error(w, msg, http.StatusNotFound, err)
+}
+
+func PodNotFound(w http.ResponseWriter, nameOrId string, err error) {
+ if errors.Cause(err) != define.ErrNoSuchPod {
+ InternalServerError(w, err)
+ }
+ msg := fmt.Sprintf("No such pod: %s", nameOrId)
+ Error(w, msg, http.StatusNotFound, err)
+}
+
+func ContainerNotRunning(w http.ResponseWriter, containerID string, err error) {
+ msg := fmt.Sprintf("Container %s is not running", containerID)
+ Error(w, msg, http.StatusConflict, err)
+}
+
+func InternalServerError(w http.ResponseWriter, err error) {
+ Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError, err)
+}
+
+func BadRequest(w http.ResponseWriter, key string, value string, err error) {
+ e := errors.Wrapf(err, "Failed to parse query parameter '%s': %q", key, value)
+ Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, e)
+}
+
+type ErrorModel struct {
+ // root cause
+ Because string `json:"cause"`
+ // error message
+ Message string `json:"message"`
+}
+
+func (e ErrorModel) Error() string {
+ return e.Message
+}
+
+func (e ErrorModel) Cause() error {
+ return errors.New(e.Because)
+}
diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go
new file mode 100644
index 000000000..0815e6eca
--- /dev/null
+++ b/pkg/api/handlers/utils/handler.go
@@ -0,0 +1,44 @@
+package utils
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+
+ log "github.com/sirupsen/logrus"
+)
+
+// WriteResponse encodes the given value as JSON or string and renders it for http client
+func WriteResponse(w http.ResponseWriter, code int, value interface{}) {
+ switch value.(type) {
+ case string:
+ w.Header().Set("Content-Type", "text/plain; charset=us-ascii")
+ w.WriteHeader(code)
+
+ if _, err := fmt.Fprintln(w, value); err != nil {
+ log.Errorf("unable to send string response: %q", err)
+ }
+ case *os.File:
+ w.Header().Set("Content-Type", "application/octet; charset=us-ascii")
+ w.WriteHeader(code)
+
+ if _, err := io.Copy(w, value.(*os.File)); err != nil {
+ log.Errorf("unable to copy to response: %q", err)
+ }
+ default:
+ WriteJSON(w, code, value)
+ }
+}
+
+func WriteJSON(w http.ResponseWriter, code int, value interface{}) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(code)
+
+ coder := json.NewEncoder(w)
+ coder.SetEscapeHTML(true)
+ if err := coder.Encode(value); err != nil {
+ log.Errorf("unable to write json: %q", err)
+ }
+}
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
new file mode 100644
index 000000000..9445298ca
--- /dev/null
+++ b/pkg/api/handlers/utils/images.go
@@ -0,0 +1,32 @@
+package utils
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/gorilla/schema"
+)
+
+// GetImages is a common function used to get images for libpod and other compatibility
+// mechanisms
+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
+ }{
+ // 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 {
+ filters = append(filters, fmt.Sprintf("reference=%s", ""))
+ }
+ return runtime.ImageRuntime().GetImagesWithFilters(filters)
+}